链表和顺序表的面试题

这篇博客记录了链表和顺序表的一些常见面试题。

包含了以下题目

// 从尾到头打印单链表 
void PrintFromTailToFront(PNode pHead);

// 删除无头单链表的非尾结点,要求:不能遍历链表 
void DeleteNotTailNode(PNode pos);

// 在无头单链表pos位置前插入值为结点data的结点 
void InsertPosFront(PNode pos, DataType data);

// 用单链表模拟实现约瑟夫环 
void JosephCircle(PNode* pHead, const int M);

// 使用冒泡排序方法对单链表进行排序 
void BubbleSort(PNode pHead);

// 单链表的逆置--三个指针 
void ReverseSList(PNode* pHead);

// 单链表的逆置--头插法 
PNode ReverseSListOP(PNode pHead);

// 合并两个有序链表,合并之后依然有序 
PNode MergeSList(PNode pHead1, PNode pHead2);

// 查找链表的中间结点,要求只能遍历一次链表 
PNode FindMiddleNode(PNode pHead);

// 查找链表的倒数第K个结点,要求只能遍历链表一次 
PNode FindLastKNode(PNode pHead, int K);

// 删除链表的倒数第K个结点,要求只能遍历链表一次 
PNode DeleteLastKNode(PNode pHead, int K);

// 判断单链表是否相交?链表不带环 
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2);

// 求不带环单链表相交交点 
PNode GetCrossNode(PNode pHead1, PNode pHead2);

// 判断链表是否带环 
PNode IsCircle(PNode pHead);

// 求环的长度 
int GetCircleLen(PNode pHead);

// 求环的入口点--注意推断过程 
PNode GetEnterNode(PNode pHead, PNode pMeetNode);

// 判断链表是否带环,链表可能带环 
int IsListCrossWithCircle(PNode pHead1, PNode pHead2);

//复杂链表
typedef struct CListNode 
{
	struct CListNode *next;
	struct CListNode *Random;
	DataType data;
}CListNode,*PCListNode;
// 复杂链表的复制 
PCListNode CopyComplexList(PCListNode pHead);

//求两个已排序单链表中的相同数据
void UnionSet(PNode L1, PNode L2);

实现:

#include "PSList.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>


//从尾到头打印单链表
void PrintFromTailToFront(PNode pHead)
{
	if (NULL == pHead)
		return;
	PNode pCur = pHead;
	if (pCur)
	{
		PrintFromTailToFront(pCur->_next);
		printf("%d ", pCur->_data);
	}
}

// 删除链表的非尾结点,要求不能遍历链表 
void DeleteNotTailNode(PNode pos)
{
	if (NULL == pos||pos->_next==NULL)
		return;
	PNode pDelNode = pos->_next;
	pos->_data = pDelNode->_data;
	pos->_next = pDelNode->_next;
	free(pDelNode);	
}

// 在链表pos位置前插入值为data的结点,不能遍历链表
void InsertPosFront(PNode pos, DataType data)
{
	if (NULL == pos)
		return;
	PNode PNewNode = BuySListNode(pos->_data);
	PNewNode->_next=pos->_next;
	pos->_next = PNewNode;
	pos->_data = data;
}

// 约瑟夫环 
void JosephCircle(PNode* pHead, const int M)
{
	assert(pHead);
	PNode pCur = *pHead;
	if (pHead == NULL)
		return;
	while (pCur->_next != pCur)
	{
		//1.报数
		int count = M;
		while (--count)
			pCur = pCur->_next;
		//2.删除
		PNode PDelNode = pCur->_next;
		pCur->_data = PDelNode->_data;
		pCur->_next = PDelNode->_next;
		free(PDelNode);
	}
	*pHead = pCur;
}

// 使用冒泡方式对单链表进行排序 
void BubbleSort(PNode pHead)
{
	if (pHead == NULL || pHead->_next == NULL)
		return;
	int i = 0;
	PNode pNext = NULL;
	for (i = 0; i < SListSize(pHead); ++i)
	{
		int flag = 0;
		PNode pCur = pHead;
		pNext = pCur->_next;
		int j = 0;
		for (j = 0; j < SListSize(pHead)-1 - i; ++j)
		{
			if (pCur->_data > pNext->_data)
			{
				int temp = pCur->_data;
				pCur->_data = pNext->_data;
				pNext->_data = temp;
				flag = 1;
			}
			pCur = pCur->_next;
		    pNext = pCur->_next;
		}
		if (flag == 0)
			break;
	}
}

// 单链表的逆序---三个指针 
void ReverseSList(PNode* pHead)
{
	assert(pHead);
	if (NULL == *pHead || NULL == (*pHead)->_next)
		return;
	PNode pPreNode = NULL;
	PNode pCurNode = *pHead;
	PNode pNextNode = NULL;
	while (pCurNode)
	{
		pNextNode = pCurNode->_next;
		pCurNode->_next = pPreNode;
		pPreNode = pCurNode;
		pCurNode = pNextNode;
	}	
	*pHead = pPreNode;
}

// 单链表的逆序---使用头插法
PNode ReverseSListOP(PNode pHead)
{
	if (pHead == NULL || pHead->_next == NULL)
		return pHead;
	PNode pNewHead = NULL;
	PNode pCurNode = pHead;
	while (pCurNode)
	{
		PNode pNextNode = pCurNode->_next;
		pCurNode->_next = pNewHead;
		pNewHead = pCurNode;
		pCurNode = pNextNode;
	}
	return pNewHead;
}

// 合并两个有序链表,合并起来依然要有序 
PNode MergeSList(PNode pHead1, PNode pHead2)
{
	if (NULL == pHead1 )
		return pHead2;
	if (NULL == pHead2)
		return pHead1;
	PNode pNewHead = NULL;
	PNode pCur1 = pHead1;
	PNode pCur2 = pHead2;

	//确定第一个节点的值
	if (pCur1->_data < pCur2->_data)
	{
		pNewHead = pCur1;
		pCur1 = pCur1->_next;
	}
	else
	{
		pNewHead = pCur2;
		pCur2 = pCur2->_next;
	}

	//向新链表中插入值
	PNode pTail = pNewHead;
	while (pCur1&&pCur2)
	{
		if (pCur1->_data < pCur2->_data)
		{
			pTail->_next = pCur1;
			pCur1 = pCur1->_next;
		}
		else
		{
			pTail->_next = pCur2;
			pCur2 = pCur2->_next;
		}
		pTail = pTail->_next;
	}

	//若一个链表有剩余,放在新链表后面
	if (pCur1)
		pTail->_next = pCur1;
	else
		pTail->_next = pCur2;
	return pNewHead;
}

// 查找链表的中间结点,要求只能遍历一次链表 
PNode FindMiddleNode(PNode pHead)
{
	//1->2->3->4->5
	//1->2->3->4->5->6
	PNode pFast = pHead;
	PNode pSlow = pHead;
	PNode pPre = pHead;
	while (pFast && pFast->_next)
	{
		pPre = pSlow;
		pFast = pFast->_next->_next;
		pSlow = pSlow->_next;
	}

	//求奇数个节点的中间节点前一个节点
	/*if (NULL == pFast)
		return pPre;*/
	return pSlow;
}

// 查找链表的倒数第K个结点 
PNode FindLastKNode(PNode pHead, int K)
{
	if (NULL == pHead || K <= 0)
		return NULL;
	PNode pFast = pHead;
	PNode pSlow = pHead;
	int count = K;

	//快的指针先走K步
	while (count--)
	{
		if (NULL == pFast)
			return NULL;
		pFast = pFast->_next;
	}

	//然后快慢指针一起走,慢指针指向的就是倒数第K个节点
	while (pFast)
	{
		pFast = pFast->_next;
		pSlow = pSlow->_next;
	}
	return pSlow;
}

// 删除链表的倒数第K个结点,要求只能遍历链表一次 
PNode DeleteLastKNode(PNode pHead, int K)
{
	if (NULL == pHead || K <= 0)
		return NULL;
	PNode pFast = pHead;
	PNode pSlow = pHead;
	PNode pPre = NULL;
	int count = K;

	//快的指针先走K步
	while (count--)
	{
		if (NULL == pFast)
			return NULL;
		pFast = pFast->_next;
	}

	//然后快慢指针一起走,慢指针指向的就是倒数第K个节点
	while (pFast)
	{
		pPre = pSlow;
		pFast = pFast->_next;
		pSlow = pSlow->_next;
	}

	//删除
	pPre->_next = pSlow->_next;
	free(pSlow);

	return pHead;
}

// 判断两个单链表是否相交---链表不带环 
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)
{
	if (NULL == pHead1 || NULL == pHead2)
		return 0;
	PNode pTail1 = pHead1;
	PNode pTail2 = pHead2;

	//找链表1和链表2的尾节点
	while (pTail1)
		pTail1 = pTail1->_next;
	while (pTail2)
		pTail2 = pTail2->_next;

	//若尾节点相同,则俩链表相交
	return pTail1 == pTail2;
}

// 如果相交 获取交点 
PNode GetCrossNode(PNode pHead1, PNode pHead2)
{
	int size1 = 0;
	int size2 = 0;
	PNode pCur1 = pHead1;
	PNode pCur2 = pHead2;
	if (!IsCrossWithoutCircle(pHead1, pHead2))
		return NULL;

	//两个链表相差的长度
	while (pCur1)
	{
		size1++;
		pCur1 = pCur1->_next;
	}
	while (pCur2)
	{
		size2++;
		pCur2 = pCur2->_next;
	}
	int gap = size1 - size2;
	pCur1 = pHead1;
	pCur2 = pHead2;
	
	//让长链表先走差值步
	if (gap > 0)
	{
		while (gap--)
			pCur1 = pCur1->_next;
	}
	else
	{
		while (gap++)
			pCur2 = pCur2->_next;
	}

	//然后两个一起走直到相等,即为交点
	while (pCur1 != pCur2)
	{
		pCur1 = pCur1->_next;
		pCur2 = pCur2->_next;
	}
	return pCur1;
}

//链表是否带环
PNode IsCircle(PNode pHead)
{
	PNode pFast = pHead;
	PNode pSlow = pHead;
	while (pFast&&pFast->_next)
	{
		pFast = pFast->_next->_next;
		pSlow = pSlow->_next;
		if (pFast == pSlow)
			return pFast;
	}
	return NULL;
}

//求环的长度
int GetCircleLen(PNode pHead)
{
	PNode pMeetNode = IsCircle(pHead);
	PNode pCur = pMeetNode->_next;
	int size = 1;
	if (NULL == pMeetNode)
		return 0;
	while (pCur != pMeetNode)
	{
		pCur = pCur->_next;
		size++;
	}
	return size;
}

//求环的入口点
PNode GetEnterNode(PNode pHead, PNode pMeetNode)
{
	if (NULL == pHead || NULL == pMeetNode)
		return NULL;
	PNode pH = pHead;
	PNode pM = pMeetNode;
	while (pH != pM)
	{
		pH = pH->_next;
		pM = pM->_next;
	}
	return pH;
}

// 判断链表是否相交,链表可能带环 
int IsListCrossWithCircle(PNode pHead1, PNode pHead2)
{
	if (NULL == pHead1 || NULL == pHead2)
		return 0;
	//1.判断两个链表是否带环
	PNode pMeetNode1 = IsCircle(pHead1);
	PNode pMeetNode2 = IsCircle(pHead2);

	//2.两个链表都不带环
	//求两个链表的最后一个元素,若最后一个元素相等则相交
	if (NULL == pMeetNode1&&NULL == pMeetNode2)
	{
		PNode pTail1 = pHead1;
		while (pTail1->_next)
			pTail1 = pTail1->_next;

		PNode pTail2 = pHead2;
		while (pTail2->_next)
			pTail2 = pTail2->_next;

		if (pTail1 == pTail2)
			return 1;
	}
	//3.两个链表都带环
	else if (pMeetNode1&&pMeetNode2)
	{
		PNode pCur = pMeetNode1;
		do
		{
			if (pCur == pMeetNode2)
				return 2;
			pCur = pCur->_next;
		} while (pCur != pMeetNode1);
	}
	return 0;
}

// 复杂链表的复制 
PCListNode CopyComplexList(PCListNode pHead)
{
	//1.向链表的每个元素后面插入值相同的元素
	PCListNode pOldNode = pHead;
	PCListNode pNewNode = NULL;
	while (pOldNode)
	{
		pNewNode = (PCListNode)malloc(sizeof(CListNode));
		pNewNode->next = NULL;
		pNewNode->Random = NULL;
		pNewNode->data = pOldNode->data;
		if (NULL == pNewNode)
			return NULL;

		pNewNode->next = pOldNode->next;
		pOldNode->next = pNewNode;
		pOldNode = pNewNode->next;
	}
	//2.改变链表的随机域
	pOldNode = pHead;
	while (pOldNode)
	{
		pNewNode = pOldNode->next;
		if (pOldNode->Random == NULL)
			pNewNode->Random = NULL;
		else
			pNewNode->Random = pOldNode->Random->next;
		pOldNode = pNewNode->next;
	}
	//3.将新链表卸下来
	pOldNode = pHead;
	PCListNode pNewHead = pOldNode->next;

	while (pOldNode->next)
	{
		pNewNode = pOldNode->next;
		pOldNode->next = pNewNode->next;
		pOldNode = pNewNode;
	}

	return pNewHead;
}

//求两个已排序单链表中的数据
void UnionSet(PNode L1, PNode L2)
{
	if (NULL == L1 || NULL == L2)
		return;
	int data = 0;
	while (L1&&L2)
	{
		if (L1->_data == L2->_data)
		{
			if(L1->_data!=data)
				printf("%d ", L1->_data);
			data = L1->_data;
			L1 = L1->_next;
		}
		else if (L1->_data < L2->_data)
			L1 = L1->_next;
		else
			L2 = L2->_next;
	}
}

顺序表和链表的比较

(1)顺序表支持随机访问,单链表不支持随机访问

(2)顺序表插入/删除数据效率很低,时间复杂度为o(N),除尾插尾删,

        单链表插入/删除效率高,时间复杂度为O(1),容易造成内存碎片

(3)顺序表的CPU高速缓存效率更高,单链表CPU高速缓存效率低

猜你喜欢

转载自blog.csdn.net/zimituanzi_/article/details/80763226