链表相关面试题

链表的基本操作在链接的博客中已经有实现https://blog.csdn.net/Damn_Yang/article/details/83689944

下面我们来看看链表相关的面试题,非常重要

下面的题目都会一个一个实现

#include<stdio.h>
typedef int DataType;

typedef struct Node
{
	DataType data;
	struct Node * next;
}Node, *pNode, LinkList, *pLinkList;

//比较顺序表和链表的优缺点 

//从尾到头打印链表
void PrintLinkTailToHead(pLinkList ppl, stack* s);

//删除一个无头单链表的非尾结点
void RmoveNodeNotTail(pLinkList *ppl, pNode pos);

//用链表实现约瑟夫环
void JosephCircle(pLinkList *ppl, int k);

//在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertNodeNotHead(pLinkList *ppl, DataType data, pNode pos);

//链表的逆置
void Reverselist(pLinkList *ppl);

//链表的冒泡排序
void BubbleSort(pLinkList *ppl);

//合并两个有序的链表,合并后依然有序
pNode Merge(pLinkList* list1, pLinkList* list2);

//合并两个有序的链表(递归版本)
pNode Merge_R(pLinkList list1, pLinkList list2);

//求单链表中间结点
pNode FindMidNode(pLinkList plist);

//求单链表倒数第K个结点
pNode FindLastKNode(pLinkList plist, int k);

//判断链表是否带环,带环返回相遇点,不带环返回NULL
pNode IsCircle(pLinkList plist);

//求环的长度
int GetCircleLength(pNode meet);

//求环的入口点
pNode GetCircleEntryNode(pLinkList plist, pNode meet);

//判断链表是否相交(假设链表不带环),相交返回1,不相交返回0
int IsCross(pLinkList plist1, pLinkList plist2);

//求两个链表的交点
pNode GetMeetNode(pLinkList plist1, pLinkList plist2);

//求两个链表中相同的数据(交集)
void UnionSet(pLinkList plist1, pLinkList plist2);

1.比较顺序表和链表的优缺点 

1.顺序表:
原理:顺序表存储是将数据元素放到一块连续的内存存储空间,存取效率高,速度快。但是不可以动态增加长度
优点:存储速度高效,可以通过下标来直接存储,创建而简单。
缺点:1.插入和删除比较慢,2.不可以增长长度
2.链表:
原理:链表存储是在程序运行过程中动态的分配空间,只要存储器还有空间,就不会发生存储溢出问题
优点:插入删除比较快,可以用不连续的空间
缺点:查找速度慢,因为需要遍历。

2.从尾到头打印单链表

//2.从尾到头打印链表
void PrintLinkTailToHead(pLinkList ppl)
{
	pNode tail = NULL;
	while (ppl != tail)
	{
		pNode cur = ppl;
		while (cur->next != tail)
		{
			cur = cur->next;
		}
		printf("%d ", cur->data);
		tail = cur;
	}
}

3.删除一个无头单链表的非尾结点

//3.删除一个无头单链表的非尾结点
void RmoveNodeNotTail(pLinkList *ppl, pNode pos)
{
	pNode del = NULL;
	pos->data = pos->next->data;//复制数据
	del = pos->next;//改变要删除的节点
	pos->next = del->next;//删除下一个节点
	free(del);
	del = NULL;
}

4.用链表实现约瑟夫环

//4.用链表实现约瑟夫环
void JosephCircle(pLinkList *ppl, int k)
{
	pNode tmp = *ppl;
	pNode cur = *ppl;
	pNode del = NULL;
	//将单链表弄成一个环
	while (tmp->next)
	{
		tmp = tmp->next;
	}
	tmp->next = *ppl;

	while (cur != cur->next)
	{
		int count = k;
		//走k-1步,清除一个
		while (--count)
		{
			cur = cur->next;
		}
		del = cur->next;
		printf("删除:%d \n", cur->data);
		cur->data = cur->next->data;//复制数据
		cur->next = del->next;//删除下一个节点
		free(del);
		del = NULL;
	}
	printf("剩余:%d\n", cur->data);
}

5.在无头单链表的一个节点前插入一个节点(不能遍历链表)

//5.在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertNodeNotHead(pLinkList *ppl, DataType data, pNode pos)
{
	pNode newNode = NULL;
	newNode = BuyNode(pos->data);
	newNode->next = pos->next;
	pos->next = newNode;
	pos->data = data;
}

6.链表的逆置

//6.链表的逆置
void Reverselist(pLinkList *ppl)
{
	pNode cur = *ppl;
	pNode tmp = NULL;
	pLinkList head = NULL;
	if (*ppl == NULL || (*ppl)->next)
	{
		return;
	}
	while (cur)
	{
		tmp = cur->next;//保存下一个节点,否则会丢失链表后面的内容
		cur->next = head;
		head = cur;
		cur = tmp;
	}
	*ppl = head;
}

7.链表的冒泡排序

//7.链表的冒泡排序
void BubbleSort(pLinkList *ppl)
{
	pNode cur = *ppl;
	pNode tail = NULL;
	while (cur != NULL)//趟数
	{
		while (cur->next != NULL)//比较次数
		{
			if (cur->data > cur->next->data)
			{
				DataType tmp = cur->data;
				cur->next = cur->next->data;
				cur->next->data = tmp;
			}
			cur = cur->next;
		}
	}
	tail = cur;
	cur = *ppl;
}

8.合并两个有序的链表,合并后依然有序

//8.合并两个有序的链表,合并后依然有序
pNode Merge(pLinkList list1, pLinkList list2)
{
	pLinkList newhead = NULL;
	//一个链表为空,一个不为空
	if (list1 == NULL)
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
	//两个链表都为空
	if ((list1 == NULL) && (list2 == NULL))
	{
		return NULL;
	}
	if (list1->data < list2->data)
	{
		newhead = list1;
		list1 = list1->next;
	}
	else
	{
		newhead = list2;
		list2 = list2->next;
	}
	//保存链表最后一个节点的位置
	pNode tail = newhead;
	//依次比较尾插
	while ((list1 != NULL) && (list2 != NULL))
	{
		if (list1->data < list2->data)
		{
			tail->next = list1;
			list1 = list1->next;
		}
		else
		{
			tail->next = list2;
			list2 = list2->next;
		}
		tail = tail->next;
	}
	//将剩余的节点插入到新链表中
	if (list1 == NULL)
	{
		tail->next = list2;
	}
	else if (list2 == NULL)
	{
		tail->next = list1;
	}
	return newhead;
}

9.合并两个有序的链表(递归版本)

//9.合并两个有序的链表(递归版本)
pNode Merge_R(pLinkList list1, pLinkList list2)
{
	pLinkList newhead = NULL;
	if (list1 == NULL)
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
	if ((list1 == NULL) && (list2 == NULL))
	{
		return NULL;
	}
	if (list1->data < list2->data)
	{
		newhead = list1;
		newhead->next = Merge_R(list1->next, list2);
	}
	else
	{
		newhead = list2;
		newhead->next = Merge_R(list2->next, list1);
	}
	return newhead;
}

10.求单链表中间结点

//10.求单链表中间结点
pNode FindMidNode(pLinkList plist)
{
	pNode first = plist;
	pNode second = plist;
	//链表没有节点或者只有一个节点返回
	if ((plist == NULL) || (plist->next == NULL))
	{
		return plist;
	}
	while ((second != NULL) && (second->next != NULL))
	{
		second = second->next->next;
		first = first->next;
	}
	return first;
}

11.求单链表倒数第K个结点

//11.求单链表倒数第K个结点
pNode FindLastKNode(pLinkList plist, int k)
{
	pNode slow = plist;
	pNode fast = plist;
	if (plist == NULL)
	{
		return plist;
	}
	//快指针走k-1步
	while (--k)
	{
		if (fast == NULL)
		{
			return NULL;
		}
		fast = fast->next;
	}
	//快慢指针一起走,快的到终点,慢指针则指向倒数第k个结点
	while (fast->next != NULL)
	{
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

12.判断链表是否带环,带环返回相遇点,不带环返回NULL

//12.判断链表是否带环,带环返回相遇点,不带环返回NULL
pNode IsCircle(pLinkList plist)
{
	pNode slow = plist;
	pNode fast = plist;
	if (plist == NULL)
	{
		return plist;
	}
	while ((fast != NULL) && (fast->next != NULL))
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
		{
			return slow;
		}
	}
	return NULL;
}

13.求环的长度

//13.求环的长度
int GetCircleLength(pNode meet)
{
	pNode cur = meet->next;
	int len = 1;
	while (cur != meet)
	{
		len++;
		cur = cur->next;
	}
	return len;
}

14.求环的入口点

//14.求环的入口点
pNode GetCircleEntryNode(pLinkList plist, pNode meet)
{
	pNode cur = plist;
	if (plist == NULL)
	{
		return NULL;
	}
	while (cur != meet)
	{
		cur = cur->next;
		meet = meet->next;
	}
	return cur;
}

15.判断链表是否相交(假设链表不带环),相交返回1,不相交返回0

//15.判断链表是否相交(假设链表不带环),相交返回1,不相交返回0
int IsCross(pLinkList plist1, pLinkList plist2)
{
	pNode cur1 = plist1;
	pNode cur2 = plist2;
	if ((plist1 == NULL) && (plist2 == NULL))
	{
		return 0;
	}
	while (cur1->next != NULL)
	{
		cur1 = cur1->next;
	}
	while (cur2->next != NULL)
	{
		cur2 = cur2->next;
	}
	if (cur1 == cur2)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

16.求两个链表的交点

//16.求两个链表的交点
pNode GetMeetNode(pLinkList plist1, pLinkList plist2)
{
	int len1 = 0;
	int len2 = 0;
	int gaps = 0;
	pNode cur1 = plist1;
	pNode cur2 = plist2;
	while (cur1)//求链表一的长度
	{
		cur1 = cur1->next;
		len1++;
	}
	while (cur2)//求链表二的长度
	{
		cur2 = cur2->next;
		len2++;
	}
	cur1 = plist1;//长链表
	cur2 = plist2;//短链表
	gaps = len1 - len2;
	if (len1 < len2)
	{
		cur1 = plist2;
		cur2 = plist1;
	}
	//长链表走gaps步
	while (gaps--)
	{
		cur1 = cur1->next;
	}
	//一起走
	while (cur1 != cur2)
	{
		cur1 = cur1->next;
		cur2 = cur2->next;
	}
	return cur1;
}

17.求两个链表中相同的数据(交集)

//17.求两个链表中相同的数据(交集)
void UnionSet(pLinkList plist1, pLinkList plist2)
{
	if ((plist1 == NULL) || (plist2 == NULL))
	{
		return;
	}
	while ((plist1 != NULL) && (plist2 != NULL))
	{
		if (plist1->data < plist2->data)
		{
			plist1 = plist1->next;
		}
		else if (plist1->data > plist2->data)
		{
			plist2 = plist2->next;
		}
		else
		{
			printf("%d ", plist1->data);
			plist1 = plist1->next;
			plist2 = plist2->next;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Damn_Yang/article/details/83866549
今日推荐