单链表的基本操作及链表面试题
程序代码如下:
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();