单链表的基本操作及链表面试题

单链表的基本操作及链表面试题


程序代码如下:


LinkList.h


#ifndef __LINKLIST_H__ 
#define __LINKLIST_H__ 

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int DataType;
typedef struct Node
{
	DataType data;
	struct Node* next;
}Node, *pNode, List, *pList;

void InitLinkList(pList* pplist);
pNode BuyNode(DataType d);
void DestroyLinkList(pList* pplist);
void PushBack(pList* pplist, DataType d);
void PopBack(pList* pplist);
void PushFront(pList* pplist, DataType d);
void PopFront(pList* pplist);
pNode Front(pNode pHead);
pNode Back(pNode pHead);
pNode Find(pList plist, DataType d);

//在指定位置之前插入一个值 
void Insert(pList* pplist, pNode pos, DataType d);
//指定位置删除 
void Erase(pList* pplist, pNode pos);
void Remove(pList* pplist, DataType d);
void RemoveAll(pList* pplist, DataType d);
void EraseNotTailNode(pNode pos);
void PrintLinkList(pList plist);
int GetListLength(pList plist);
//链表面试题 

//1. 逆序打印单项链表 
void PrintTailToHead(pList plist);
//2.获取单链表的最后一个节点
pNode SListBack(pList plist);
// 在单链表非头结点前插入新节点,要求不能遍历链表 
void InsertPosFront(pNode pos, DataType data);
// 用冒泡排序对单链表进行排序 
void BubbleSort(pNode* pHead);
// 查找单链表的中间结点,要求只能遍历一次链表 
pNode FindMiddleNode(pNode pHead);
// 查找单链表的倒数第K个结点,要求只能遍历一次链表 
pNode FindLastKNode(pNode pHead, int K);
// 单链表的逆置 
void ReverseList(pNode* pHead);
pNode ReverseListOP(pNode pHead);
// 合并两个有序链表,合并成功后依然有序 
pNode MergeList(pNode pHead1, pNode pHead2);
// 用单链表模拟实现约瑟夫环 
pNode JosephCircle(pNode pHead, int M);
// 检测单链表是否带环 
pNode HasListCircle(pNode pHead);
// 求环的长度 
int GetCircleLen(pNode pHead);
// 求环的入口点 
pNode GetEnterNode(pNode pHead, pNode pMeetNode);
// 判断两个单链表是否相交(链表不带环) 
int IsListCross(pNode pHead1, pNode pHead2);
// 若相交,求交点 
pNode GetCrossNode(pNode pHead1, pNode pHead2);
// 检测两个链表是否相交,链表可能带环 
pNode IsListCrossWithCircle(pNode pHead1, pNode pHead2);
#endif //__LINKLIST_H__

LinkList.c

#include "Linklist Interface.h"

void InitLinkList(pList* pplist)
{
	assert(pplist);
	*pplist = NULL;
}

pNode BuyNode(DataType d)
{
	pNode newNode = (pNode)malloc(sizeof(Node));
	/*if (newNode == NULL)
	{
		perror("malloc");
		exit(EXIT_FAILURE);
	}*/
	if (NULL == newNode)
	{
		assert(0);
		return NULL;
	}
	newNode->data = d;
	newNode->next = NULL;
	newNode->rand = NULL;
	return newNode;
}

void DestroyLinkList(pList* pplist)
{
	assert(pplist);
	pNode cur = *pplist;
	while (cur)
	{
		pNode del = cur;
		cur = cur->next;
		free(del);
		del = NULL;
	}
	*pplist = NULL;
}

void PushBack(pList* pplist, DataType d)
{
	assert(pplist);
	pNode newNode = BuyNode(d);
	pNode tail = *pplist;
	if (*pplist == NULL)
	{
		*pplist = newNode;
		return;
	}
	while (tail->next)
	{
		tail = tail->next;
	}
	tail->next = newNode;
}

void PopBack(pList* pplist)
{
	assert(pplist);
	pNode tail = *pplist;
	pNode pre = NULL;
	if (*pplist == NULL)
		return;
	if (tail->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
		return;
	}
	while (tail->next != NULL)
	{
		pre = tail;
		tail = tail->next;
	}
	free(tail);
	pre->next = NULL;
}

void PushFront(pList* pplist, DataType d)
{
	assert(pplist);
	if (*pplist == NULL)
		*pplist = BuyNode(d);
	else
	{
		pNode newNode = BuyNode(d);
		newNode->next = *pplist;
		*pplist = newNode;
	}
}

void PopFront(pList* pplist)
{
	assert(pplist);
	pNode cur = *pplist;
	if (*pplist == NULL)
		return;
	*pplist = cur->next;
	free(cur);
	cur = NULL;
}

pNode Front(pNode pHead)
{
	if (NULL == pHead)
		return NULL;
	return pHead;
}

pNode Back(pNode pHead)
{
	if (NULL == pHead)
		return NULL;
	while (NULL != pHead->next)
		pHead = pHead->next;
	return pHead;
}

pNode Find(pList plist, DataType d)
{
	while (plist)
	{
		if (d == plist->data)
			return plist;
		plist = plist->next;
	}
	return NULL;
}

//在指定位置之前插入一个值 
void Insert(pList* pplist, pNode pos, DataType d)
{
	assert(pplist);
	assert(pos);
	if (*pplist == NULL)
		PushFront(pplist, d);
	else
	{
		pNode cur = NULL;
		pNode tail = *pplist;
		while (tail->next != pos)
			tail = tail->next;
		cur = BuyNode(d);
		tail->next = cur;
		cur->next = pos;
	}
}
//指定位置删除 
void Erase(pList* pplist, pNode pos)
{
	assert(pplist);
	assert(pos);
	if (*pplist == NULL)
		return;
	if ((NULL == (*pplist)->next) || (*pplist == pos))
		PopFront(pplist);
	else
	{
		pNode tmp = *pplist;
		while (tmp->next != pos)
			tmp = tmp->next;
		tmp->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

void Remove(pList* pplist, DataType d)
{
	assert(pplist);
	if (NULL == *pplist)
		return;
	if (d == (*pplist)->data)
		PopFront(pplist);
	else
	{
		pNode tmp = *pplist;
		while (tmp->next->data != d)
			tmp = tmp->next;
		pNode pos = tmp->next;
		tmp->next = pos->next;
		free(pos);
		pos = NULL;
		//pNode pos = Find(*pplist, d);
	}
}

void RemoveAll(pList* pplist, DataType d)
{
	assert(pplist);
	pNode tmp = *pplist;
	pNode cur = *pplist;
	if (NULL == *pplist)
		return;
	if (d == (*pplist)->data)
		PopFront(pplist);
	while (cur)
	{
		if (d == cur->data)
		{
			tmp->next = cur->next;
			free(cur);
			cur = tmp->next;
		}
		else
		{
			tmp = cur;
			cur = cur->next;
		}
	}
}

void EraseNotTailNode(pNode pos)
{
	assert(pos);
	pNode del = pos->next;
	if (NULL == del)
		return;
	pos->data = del->data;
	pos->next = del->next;
	free(del);
	del = NULL;
}

void PrintLinkList(pList plist)
{
	pNode tmp = plist;
	while (tmp)
	{
		printf("%d-->", tmp->data);
		tmp = tmp->next;
	}
	printf("NULL\n");
}

int GetListLength(pList plist)
{
	int count = 0;
	while (plist)
	{
		count++;
		plist = plist->next;
	}
	return count;
}
//链表面试题 

//1. 逆序打印单项链表 
void PrintTailToHead(pList plist)
{
	if (plist == NULL)
	{
		printf("NULL");
		return;
	}
	else
	{
		PrintTailToHead(plist->next);
		printf("<--%d", plist->data);
	}
	//printf("\n");
}
//2.获取单链表的最后一个节点
pNode SListBack(pList plist)
{
	if (NULL == plist)
		return NULL;
	while (plist->next)
	{
		plist = plist->next;
	}
	return plist;
}

// 在单链表非头结点前插入新节点,要求不能遍历链表 
void InsertPosFront(pNode pos, DataType data)
{
	pNode pNewNode;
	pNode cur;
	DataType tmp = 0;

	assert(pos);
	if (NULL == pos)
		return;

	pNewNode = BuyNode(data);
	cur = pos;
	pNewNode->next = cur->next;
	cur->next = pNewNode;

	tmp = pNewNode->data;
	pNewNode->data = cur->data;
	cur->data = tmp;
}

// 用冒泡排序对单链表进行排序 
void BubbleSort(pNode* pHead)
{
	pNode cur = (*pHead);
	pNode tail = NULL;
	DataType tmp = 0;

	if (NULL == (*pHead) || NULL == (*pHead)->next)
		return;

	while (cur != tail)
	{
		while (cur->next != tail)
		{
			if (cur->data > cur->next->data)
			{
				tmp = cur->next->data;
				cur->next->data = cur->data;
				cur->data = tmp;
			}
			cur = cur->next;
		}
		tail = cur;
		cur = (*pHead);
	}
}

// 查找单链表的中间结点,要求只能遍历一次链表 
pNode FindMiddleNode(pNode pHead)
{
	pNode fast = pHead;
	pNode slow = pHead;

	if (NULL == pHead)
		return NULL;

	while (fast)
	{
		if (fast->next)
			fast = fast->next->next;
		else
		{
			fast = fast->next;
			break;
		}
		slow = slow->next;
	}
	return slow;
}

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

	if (NULL == pHead || 0 == K)
		return NULL;

	while(K--)
		fast = fast->next;
	while (fast)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}

// 单链表的逆置 
void ReverseList(pNode* pHead)
{
	pNode cur = (*pHead)->next;
	pNode tmp = NULL;

	assert(pHead);

	if (NULL == (*pHead))
		return;
	(*pHead)->next = NULL;

	while (cur)
	{
		tmp = cur;
		cur = cur->next;
		tmp->next = (*pHead);
		(*pHead) = tmp;
	}
}

pNode ReverseListOP(pNode pHead)
{
	pNode cur = pHead;
	pNode NewHead = NULL;
	pNode tmp = NULL;

	if (NULL == pHead || NULL == pHead->next)
		return NULL;

	while (cur)
	{
		tmp = cur->next;
		cur->next = NewHead;
		NewHead = cur;
		cur = tmp;
	}
	return NewHead;

}

// 合并两个有序链表,合并成功后依然有序 
pNode MergeList(pNode pHead1, pNode pHead2)
{
	pNode pNewNode = NULL;
	pNode pNewHead = NULL;
	pNode p1 = pHead1;
	pNode p2 = pHead2;

	if (NULL == p1)
		return p2;
	if (NULL == p2)
		return p1;

	if (p1->data > p2->data)
	{
		pNewNode = p2;
		p2 = p2->next;
		pNewHead = pNewNode;
	}
	else
	{
		pNewNode = p1;
		p1 = p1->next;
		pNewHead = pNewNode;
	}

	while (NULL != p1 && NULL != p2)
	{
		if (p1->data > p2->data)
		{
			pNewNode->next = p2;
			p2 = p2->next;
			pNewNode = pNewNode->next;
		}
		else
		{
			pNewNode->next = p1;
			p1 = p1->next;
			pNewNode = pNewNode->next;
		}
	}

	if (NULL == p1)
	{
		pNewNode->next = p2;
		return pNewHead;
	}
	if (NULL == p2)
	{
		pNewNode->next = p1;
		return pNewHead;
	}
}

// 用单向循环链表模拟实现约瑟夫环 
pNode JosephCircle(pNode pHead, int M)
{
	int num;
	pNode pre = NULL;
	pNode cur = pHead;
	if (NULL == pHead)
		return NULL;
	if (1 != M)
	{
		while (cur->next != cur)
		{
			num = M;
			while (--num)
			{
				pre = cur;
				cur = cur->next;
			}
			pre->next = cur->next;
			free(cur);
			cur = pre->next;
		}
		return cur;
	}
	else
	{
		printf("M值为1\n");
		return NULL;
	}
}

// 检测单链表是否带环 
pNode HasListCircle(pNode pHead)
{
	pNode pFast = pHead;
	pNode pSlow = pHead;

	if (NULL == pHead || NULL == pHead->next)
		return NULL;
	while (NULL != pFast->next)
	{
		if (NULL != pFast->next->next)
		{
			pFast = pFast->next->next;
			pSlow = pSlow->next;
		}
		else
			return NULL;
		if (pSlow == pFast)
			return pFast;
	}
	return NULL;

}
// 求环的长度 
int GetCircleLen(pNode pHead)
{
	int count = 0;
	pNode pFast = pHead;
	pNode pSlow = pHead;

	if (NULL == pHead || NULL == pHead->next)
		return 0;
	while (NULL != pFast->next)
	{
		if (NULL != pFast->next->next)
		{
			pFast = pFast->next->next;
			pSlow = pSlow->next;
		}
		else
			return 0;
		if (pSlow == pFast)
		{
			pFast = pFast->next;
			count++;
			while (pSlow != pFast)
			{
				pFast = pFast->next;
				count++;
			}
			return count;
		}
	}
	return 0;
}

// 求环的入口点 
pNode GetEnterNode(pNode pHead, pNode pMeetNode)
{
	pNode pFast = pHead;
	pNode pSlow = pMeetNode;
	while (pSlow != pFast)
	{
		pFast = pFast->next;
		pSlow = pSlow->next;
	}
	return pFast;
}

// 判断两个单链表是否相交(链表不带环) 
int IsListCross(pNode pHead1, pNode pHead2)
{
	if (NULL == pHead1 || NULL == pHead2)
		return 0;
	while (pHead1->next)
		pHead1 = pHead1->next;
	while (pHead2->next)
		pHead2 = pHead2->next;
	if (pHead1 == pHead2)
		return 1;
	else
		return 0;
}

// 若相交,求交点 
pNode GetCrossNode(pNode pHead1, pNode pHead2)
{
	int steps = 0;
	int len1 = GetListLength(pHead1);
	int len2 = GetListLength(pHead2);
	int ret = IsListCross(pHead1, pHead2);
	if(ret == 0 || NULL == pHead1 || NULL == pHead2)
		return NULL;
	steps = len1 > len2 ? (len1 - len2) : (len2 - len1);
	while (steps--)
		len1 > len2 ? (pHead1 = pHead1->next) : (pHead2 = pHead2->next);
	while (pHead1 != pHead2)
	{
		pHead1 = pHead1->next;
		pHead2 = pHead2->next;
	}
	return pHead1;
}

// 检测两个链表是否相交,链表可能带环,若相交,求交点 
pNode IsListCrossWithCircle(pNode pHead1, pNode pHead2)
{
	pNode M1 = HasListCircle(pHead1);//判断是否带环,若带环返回相遇点
	pNode M2 = HasListCircle(pHead2);
	pNode entryNode1 = GetEnterNode(pHead1, M1);//返回入口点
	pNode entryNode2 = GetEnterNode(pHead2, M2);

	pNode entryNext1 = entryNode1->next;//保留入口点的next,用于恢复环
	pNode entryNext2 = entryNode2->next;
	pNode meet = NULL;//如果是环外相交,用于保存相交点
	pNode cur = M1->next;
	if (NULL == M1 && NULL == M2)//两个都不带环,转换为Y型相交问题
		return GetCrossNode(pHead1, pHead2);
	else if (M1 && M2)//两个都带环,分三种情况讨论
	{
		while (cur != M2 && cur != M1)
			cur = cur->next;
		if (cur != M2)//1.不相交
			return NULL;
		else
		{
			if (entryNode1 == entryNode2)//2.环外相交
			{
				entryNode1->next = NULL;
				entryNode2->next = NULL;
				meet = GetCrossNode(pHead1, pHead2);
				entryNode1->next = entryNext1;
				entryNode2->next = entryNext2;
				return meet;
			}
			else//3.环内相交
			{
				return entryNode2;
			}
		}
	}
	else//一个带环,一个不带环(一定不相交)
		return NULL;
}

test.c

#include "Linklist Interface.h"

void Test1()
{
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	PrintLinkList(plist);
	PopBack(&plist);
	PrintLinkList(plist);
	DestroyLinkList(&plist);
	PrintLinkList(plist);
	
}

void Test2()
{
	pList plist;
	InitLinkList(&plist);
	PushFront(&plist, 5);
	PushFront(&plist, 4);
	PushFront(&plist, 3);
	PushFront(&plist, 2);
	PushFront(&plist, 1);
	PrintLinkList(plist);
	PopFront(&plist);
	PrintLinkList(plist);
	pNode pos = Find(plist, 4);
	if (NULL == pos)
		printf("该元素不在链表中\n");
	else
	{
		//在指定位置之前插入一个值 
		Insert(&plist, pos, 4);
		PrintLinkList(plist);
		//指定位置删除 
		Erase(&plist, pos);
		PrintLinkList(plist);
	}
}

void Test3()
{
	pList plist;
	InitLinkList(&plist);
	PushFront(&plist, 6);
	PushFront(&plist, 5);
	PushFront(&plist, 3);
	PushFront(&plist, 4);
	PushFront(&plist, 2);
	PushFront(&plist, 5);
	PushFront(&plist, 1);
	PrintLinkList(plist);

	Remove(&plist, 4);
	PrintLinkList(plist);

	RemoveAll(&plist, 5);
	PrintLinkList(plist);

	EraseNotTailNode(Find(plist, 3));
	PrintLinkList(plist);

	int num = GetListLength(plist);
	printf("%d\n", num);
	//链表面试题 

	//1. 逆序打印单项链表 
	PrintTailToHead(plist);
	printf("\n");
	//2.获取单链表的最后一个节点
	pNode pos = SListBack(plist);
	if (NULL == pos)
		printf("%d\n",0);
	else
		printf("%d\n", pos->data);
}

void Test4()
{
	pList plist;
	pNode pFront, pBack;
	InitLinkList(&plist);
	PushFront(&plist, 1);
	PushFront(&plist, 2);
	PushFront(&plist, 4);
	PushFront(&plist, 5);
	PushFront(&plist, 6);
	PrintLinkList(plist);

	InsertPosFront(Find(plist, 2), 3);
	PrintLinkList(plist);

	BubbleSort(&plist);
	PrintLinkList(plist);

	pNode pos = FindMiddleNode(plist);
	if (NULL == pos)
		printf("%d\n", 0);
	else
		printf("链表的中间节点为:%d\n", pos->data);
	int k = 2;
	pos = FindLastKNode(plist, k);
	if (NULL == pos)
		printf("%d\n", 0);
	else
		printf("链表的倒数第%d个节点为:%d\n", k, pos->data);

	ReverseList(&plist);
	PrintLinkList(plist);

	plist = ReverseListOP(plist);
	PrintLinkList(plist);

	pFront = Front(plist);
	pBack = Back(plist);
	pBack->next = pFront;
}

Test5()
{
	pList plist, plist1, plist2;
	pNode pFront, pBack1, pBack2, pCrossNode, pEnterNode;

	InitLinkList(&plist1);
	PushFront(&plist1, 10);
	PushFront(&plist1, 8);
	PushFront(&plist1, 5);
	PushFront(&plist1, 2);
	PushFront(&plist1, 1);
	PrintLinkList(plist1);

	InitLinkList(&plist2);
	PushFront(&plist2, 21);
	PushFront(&plist2, 13);
	PushFront(&plist2, 9);
	PushFront(&plist2, 7);
	PushFront(&plist2, 6);
	PushFront(&plist2, 4);
	PushFront(&plist2, 3);
	PrintLinkList(plist2);

	// 判断两个单链表是否相交(链表不带环) 
	pBack1 = Back(plist1);
	pCrossNode = FindLastKNode(plist2, 5);
	pBack1->next = pCrossNode;
	if (IsListCross(plist1, plist2))
		printf("两个链表相交\n");
	else
		printf("两个链表不相交\n");
	// 若相交,求交点 
	printf("pCrossNode == %d\n", GetCrossNode(plist1, plist2)->data);

	// 检测两个链表是否相交,链表可能带环,若相交,求交点 
	pBack2 = Back(plist2);
	pEnterNode = FindLastKNode(plist2, 3);
	pBack2->next = pEnterNode;
	pCrossNode = IsListCrossWithCircle(plist1, plist2);
	if (NULL == pCrossNode)
		printf("两个链表不相交\n");
	else
		printf("两个链表相交,pCrossNode == %d\n", pCrossNode->data);

	pBack1->next = NULL;
	pBack2->next = NULL;
	plist = MergeList(plist1, plist2);
	PrintLinkList(plist);

	// 用单向循环链表模拟实现约瑟夫环
	pFront = Front(plist);
	pBack1 = Back(plist);
	pBack1->next = pFront; 
	printf("模拟实现约瑟夫环,最后留下来的是%d\n", JosephCircle(plist, 3)->data);
}

Test6()
{
	pList plist;
	pNode pFront, pBack, pMeetNode, pEnterNode;

	InitLinkList(&plist);
	PushFront(&plist, 9);
	PushFront(&plist, 8);
	PushFront(&plist, 7);
	PushFront(&plist, 6);
	PushFront(&plist, 5);
	PushFront(&plist, 4);
	PushFront(&plist, 3);
	PushFront(&plist, 2);
	PushFront(&plist, 1);

	pBack = Back(plist);
	pEnterNode = FindLastKNode(plist, 6);
	pBack->next = pEnterNode;

	// 检测单链表是否带环 
	pMeetNode = HasListCircle(plist);
	if (NULL != pMeetNode)
		printf("链表带环\n");
	else
		printf("链表不带环\n");
	// 求环的长度 
	printf("lenth = %d\n", GetCircleLen(plist));
	// 求环的入口点 
	printf("EnterNode == %d\n", GetEnterNode(plist, pMeetNode)->data);
}

int main()
{
	//Test1();
	//Test2();
	//Test3();
	Test4();
	system("pause");
	return 0;

}

程序运行结果如下:


test1();
在这里插入图片描述

test2();
在这里插入图片描述

test3();
在这里插入图片描述

test4();
在这里插入图片描述

test5();
在这里插入图片描述

test6();
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值