相关博客链接:
C语言实现 单向链表
https://blog.csdn.net/qq_37941471/article/details/72961495
C语言实现单链表面试题—基础篇
https://blog.csdn.net/qq_37941471/article/details/78033970
C语言实现单链表面试题—进阶
https://blog.csdn.net/qq_37941471/article/details/80437143
代码:
List.h List.c test.c
- List.h :
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#include <assert.h>
typedef int DataType;
typedef struct ListNode
{
DataType data;//节点存放的数据
struct ListNode* next;//下一个节点
}ListNode;
ListNode* BuyNode(DataType x);//创建节点
void PrintList(ListNode *plist);//打印链表
void PushBack(ListNode **pplist,DataType x);//尾插
void PopBack(ListNode **pplist);//尾删
void PushFront(ListNode **pplist,DataType x);//头插
void PopFront(ListNode **pplist);//头删
ListNode* Find(ListNode *plist,DataType x);//查找x
void Insert(ListNode **pplist,ListNode* pos,DataType x);//在pos位置前面插入节点
void Erase(ListNode **pplist,ListNode *pos);//删除pos节点
void PrintTailToHead(ListNode *plist);//2.从尾到头打印单链表
void EraseNonTail(ListNode* pos);//3.删除一个无头单链表的非尾节点
void InsertNonHead(ListNode* pos,DataType x);//4.在无头单链表的一个节点前插入一个节点
ListNode* JosepRing(ListNode* list,DataType k);//5.单链表实现约瑟夫环
void Reverse(ListNode** pplist);//6.翻转/逆置链表
void SortList(ListNode* list);//7.单链表排序(冒泡排序)
ListNode* Merge(ListNode* list1,ListNode* list2);//8.合并两个有序单链表,合并后依然有序
ListNode* FindMidNode(ListNode* plist);//9.查找链表的中间节点,要求只能遍历一次
void FindKNode(ListNode* plist,int k);//10.查找单链表的倒数第k个节点,要求只能遍历一次
ListNode* IsCycle(ListNode* plist);//11.判断链表是否带环?
ListNode* GetEntry(ListNode* plist, ListNode* MeetNode);//若带环,求其入口点
int GetCycle_Length(ListNode* MeetNode);//若带环,求环的长度
int IsCross_NoCycle(ListNode* plist1,ListNode* plist2);//12.判断两个链表是否相交?(假设链表不带环)
ListNode* GetCrossNode(ListNode* plist1, ListNode* plist2);//若相交,求交点
ListNode* IsCross_Cycle(ListNode* plist1,ListNode* plist2);//13.判断两个链表是否相交?若相交,求交点。(假设链表可能带环)
- List.c :
#include "List.h"
ListNode* BuyNode(DataType x)//创建节点
{
ListNode* Node = (ListNode*)malloc(sizeof(ListNode));//开辟空间
Node->data = x;
Node->next = NULL;
return Node;
}
void PrintList(ListNode *plist)//打印链表
{
ListNode* cur = plist;
while (cur)
{
printf("%d->",cur->data);
cur = cur->next ;
}
printf("NULL\n");
}
void PushBack(ListNode **pplist,DataType x)//尾插
{
assert(pplist);
//1. 链表为空
//2. 一个节点
//3. 多个节点
if( *pplist == NULL )
{
*pplist = BuyNode(x);
}
else if( (*pplist)->next == NULL )
{
(*pplist)->next = BuyNode(x);
}
else //多节点
{
ListNode* cur = *pplist;
while ( cur->next ) //终止条件(找最后一个节点):cur->next == NULL;所以继续条件恰好相反
{
cur = cur->next ;
}
cur->next = BuyNode(x);
}
}
void PopBack(ListNode **pplist)//尾删
{
assert(pplist);
//1. 链表为空
//2. 一个节点
//3. 多个节点
if( *pplist == NULL )
return;
else if( (*pplist)->next == NULL )
{
free(*pplist);//malloc free()
*pplist = NULL;
}
else//多节点
{
ListNode* prev = *pplist;
ListNode* cur = *pplist;
while( cur->next )
{
prev = cur;
cur = cur->next ;
}
free(cur);
cur = NULL;
prev->next = NULL;
}
}
void PushFront(ListNode **pplist,DataType x)//头插
{
assert(pplist);
//1. 链表为空
//2. 非空
if( *pplist == NULL )
{
*pplist = BuyNode(x);
}
else //非空
{
ListNode* Node = BuyNode(x);
Node->next = *pplist;
*pplist = Node;
}
}
void PopFront(ListNode **pplist)//头删
{
assert(pplist);
//1. 链表为空
//2. 一个节点
//3. 多节点
if( *pplist == NULL )
return;
else if ( (*pplist)->next == NULL )
{
free(*pplist);
*pplist = NULL;
}
else//多节点
{
ListNode* tmp = *pplist;
ListNode* Next = (*pplist)->next ;
*pplist = Next;
free(tmp);
}
}
ListNode* Find(ListNode *plist,DataType x)//查找x
{
assert(plist);
while( plist )
{
if( plist->data == x )
return plist;
plist = plist->next ;
}
return NULL;
}
void Insert(ListNode **pplist,ListNode* pos,DataType x)//在pos位置前面插入节点
{
assert(pplist&&pos);
//1. pos为头结点,则进行头插
//2. pos为其他节点
if( *pplist == pos )//pos为头结点
{
PushFront(pplist,x);
}
else //pos为其他节点
{
ListNode* tmp = BuyNode(x);
ListNode* prev = *pplist ;
ListNode* cur = *pplist;
//while( cur )
//{
// if( cur->next == pos )//找pos的prev
// prev = cur;
// cur = cur->next ;
//}
while( prev->next != pos )//终止条件:prev->next == pos,则找到了prev
{
prev = prev->next ;
}
prev->next = tmp;
tmp->next = pos;
}
}
void Erase(ListNode **pplist,ListNode *pos)//删除pos节点
{
assert(pplist&&pos);
//1. 头删
//2. 尾删
//3. 中间删
if( *pplist == pos )//头删
{
PopFront(pplist);
}
else if( pos->next == NULL ) //尾删
{
PopBack(pplist);
}
else //中间删
{
ListNode* prev = *pplist;
while( prev->next != pos )
{
prev = prev->next ;
}
prev->next = pos->next ;
free(pos);
pos = NULL;
}
}
void PrintTailToHead(ListNode *plist)//2.从尾到头打印单链表
{
if( plist == NULL )
return;
PrintTailToHead(plist->next);
printf("%d ",plist->data);
}
void EraseNonTail(ListNode* pos)3.删除一个无头单链表的非尾节点
{
//1 2 3 4
//3
//删除一个无头非尾节点,即将目标节点3的下一个节点next4的值赋给3所在的位置,然后将pos->next指向next->next,并释放next
ListNode* Next = pos->next ;
assert(pos&&Next);//断言Next不为空 因为是一个非尾节点
pos->data = Next->data ;
pos->next = Next->next ;
free(Next);
}
void InsertNonHead(ListNode* pos,DataType x)//4.在无头单链表的一个节点前插入一个节点
{
//1 2 3 5
//5前面加4
//创建新的节点tmp,给其data为5,然后将5的节点的(pos)next指向tmp,将tmp->next 指向 next,最后将5改成x(4)
ListNode* Next = NULL;
ListNode* tmp = BuyNode( pos->data );
assert(pos);
Next = pos->next ;
pos->next = tmp;
tmp->next = Next;
pos->data = x;
}
ListNode* JosepRing(ListNode* list,DataType k)//5.单链表实现约瑟夫环
{
int count = k;
ListNode* cur = list;
ListNode* prev = NULL;
assert(list);
if (NULL == list)
return NULL;
while ( cur->next != cur )//终止条件:cur->next == cur(只剩下一个节点)
{
count = k;
while (--count)
{
prev = cur;
cur = cur->next ;
}
//走到这里就开始删除,然后继续循环
printf ("删除第%d个人 \n",cur->data);
prev->next = cur->next ;
free(cur);
cur = prev->next ;
}
return cur;
}
void Reverse(ListNode** pplist)//6.翻转/逆置链表
{
ListNode* prev = *pplist;
ListNode* cur = prev->next ;
ListNode* Next = NULL;
assert(pplist);
//1. 空链表和只有一个节点 都不需要逆置
//2. 多节点 逆置
if( *pplist == NULL || ((*pplist)->next == NULL) )
{
return;
}
//逆置
while(cur)
{
Next = cur->next ;
cur->next = prev;
prev = cur;
cur = Next;
}
(*pplist)->next = NULL;
*pplist = prev ;
}
void SortList(ListNode* list)//7.单链表排序(冒泡排序)
{
ListNode* cur = list;
ListNode* next = cur->next ;
ListNode* tail = NULL;
int exchange = 0;
assert(list);
if( list == NULL || (list->next == NULL) )
{
return;
}
tail = NULL;
cur = list;
next = cur->next ;
while( cur != tail )
{
while( next != tail )
{
if( cur->data > next->data )
{
DataType tmp = cur->data ;
cur->data = next->data ;
next->data = tmp;
exchange = 1;
}
cur = cur->next ;
next = next->next ;
}
if( 0 == exchange )
{
break;
}
tail = cur;
cur = list;
next = cur->next ;
}
}
ListNode* Merge(ListNode* list1,ListNode* list2)//8.合并两个有序单链表,合并后依然有序
{
ListNode* list = NULL;
ListNode* cur ;
assert(list1&&list2);
//1. list1空链表
//2. list2空链表
//3. 都非空
if( list1 == NULL )
return list2;
if( list2 == NULL )
return list1;
if( list1->data > list2->data )
{
list = list2;
list2 = list2->next ;
}
else
{
list = list1;
list1 = list1->next ;
}
cur = list;
while( list1&&list2 )
{
if( list1->data > list2->data )
{
cur->next = list2;
cur = cur->next ;
list2 = list2->next ;
}
else
{
cur->next = list1;
cur = cur->next ;
list1 = list1->next ;
}
}
if( list1 == NULL )
cur->next = list2;
if( list2 == NULL )
cur->next = list1;
return list;
}
ListNode* FindMidNode(ListNode* plist)//9.查找链表的中间节点,要求只能遍历一次
{
ListNode* slow = plist;
ListNode* fast = plist;
/*assert(plist);*/
if( plist == NULL )
return NULL;
while( fast && (fast->next) && (fast->next->next) )
{
fast = fast->next->next ;
slow = slow->next ;
}
return slow;
}
void FindKNode(ListNode* plist,int k)//10.查找单链表的倒数第k个节点,要求只能遍历一次
{
ListNode* slow = plist;
ListNode* fast = plist;
int count = k;
assert(plist);
if( plist == NULL )
return;
while( fast && (fast->next) )
{
if( --count > 0)
{
fast = fast->next;
}
fast = fast->next ;
slow = slow->next ;
/*fast = fast->next ;
if( --count <= 0 )
{
slow = slow->next ;
}*/
}
printf("倒数第%d个数是%d\n",k,slow->data);
}
ListNode* IsCycle(ListNode* plist)//11.判断链表是否带环?
{
ListNode* slow = plist;
ListNode* fast = plist;
if( plist == NULL || plist->next == NULL )
return NULL;
while( fast && fast->next )//如果不带环,快指针先走到尾(终止条件)
{
fast = fast->next->next;
slow = slow->next;
if( slow == fast )//如果带环,快慢指针一定会相遇
return slow;
}
return NULL;
}
ListNode* GetEntry(ListNode* plist, ListNode* MeetNode)//若带环,求其入口点。
{
assert( plist&&MeetNode);
while( plist != MeetNode )//plist == MeetNode找到入口点
{
plist = plist->next ;
MeetNode = MeetNode->next ;
}
return plist;
}
int GetCycle_Length(ListNode* MeetNode)//若带环,求环的长度
{
ListNode* cur = MeetNode->next ;
int num = 1;
while( cur != MeetNode )
{
++num;
cur = cur->next;
}
return num;
}
int IsCross_NoCycle(ListNode* plist1,ListNode* plist2)//12.判断两个链表是否相交?(假设链表不带环)
{
assert(plist1&&plist2);
if( plist1 == NULL || plist2 == NULL )
return -1;
while(plist1->next)
{
plist1 = plist1->next ;
}
while(plist2->next)
{
plist2 = plist2->next;
}
if( plist1 == plist2 )
return 1;
}
ListNode* GetCrossNode(ListNode* plist1, ListNode* plist2)//若相交,求交点
{
ListNode* longlist = plist1,*cur1 = plist1;
ListNode* shortlist = plist2,*cur2 = plist2;
int len1 = 0,len2 = 0;
int gap;
//求两个链表的长度,判断哪个长?
while(cur1)
{
len1++;
cur1 = cur1->next;
}
while(cur2)
{
len2++;
cur2 = cur2->next;
}
if( len1<len2 )
{
longlist = plist2;
shortlist = plist1;
}
gap = abs(len1-len2);
//长的先走gap步,gap--(gap步),--gap(gap-1步)
while(gap--)
{
longlist = longlist->next ;
}
//一起走,相遇点就是交点
while( longlist != shortlist )
{
longlist = longlist->next ;
shortlist = shortlist->next ;
}
return shortlist;
}
ListNode* IsCross_Cycle(ListNode* plist1,ListNode* plist2)//13.判断两个链表是否相交?若相交,求交点。(假设链表可能带环)
{
//求链表带环的相遇点
ListNode* MeetNode1 = IsCycle(plist1) ;
ListNode* MeetNode2 = IsCycle(plist2) ;
ListNode* entry1 ;
ListNode* entry2 ;
ListNode* meet,*cur1;
//判断链表是否带环
if( MeetNode1 == NULL || MeetNode2 == NULL )
return NULL;//其中一个链表不带环,则不会相交,返回NULL
//两个链表都带环,相交的两种情况
//1.相同的入口点
//2.不同的入口点
entry1 = GetEntry(plist1,MeetNode1);
entry2 = GetEntry(plist2,MeetNode2);
if( entry1 == entry2 )//相同的入口点,返回交点
{
entry1->next = NULL;
entry2->next = NULL;
meet = GetCrossNode(plist1,plist2);
return meet;
}
//不同的入口点的情况(判断条件:从MeetNode1开始遍历链表,如果找到和MeetNode2相等的节点,则证明共用环)
//如果相交,返回任意一个入口点
cur1 = MeetNode1->next ;
while( cur1 != MeetNode1 && cur1 != MeetNode2 )
{
cur1 = cur1->next ;
}
if( cur1 == MeetNode2 )
return entry1;
return NULL;//不相交
}
- test.c :
#include "List.h"
void test1()
{
ListNode* list = NULL;
PushBack(&list,1);
PushBack(&list,2);
PushBack(&list,3);
PushBack(&list,4);
PrintList(list);
PopBack(&list);//尾删
PrintList(list);
PopBack(&list);
PopBack(&list);
PopBack(&list);
PopBack(&list);//一个节点
PrintList(list);
PopBack(&list);
PopBack(&list);
PopBack(&list);
PopBack(&list);
PopBack(&list);//空链表
PrintList(list);
}
void test2()
{
ListNode* list = NULL;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,2);
PushFront(&list,1);
PrintList(list);
PopFront(&list);//尾删
PrintList(list);
PopFront(&list);
PopFront(&list);
PopFront(&list);
PopFront(&list);//一个节点
PrintList(list);
PopFront(&list);
PopFront(&list);
PopFront(&list);
PopFront(&list);
PopFront(&list);//空链表
PrintList(list);
}
void test3()
{
ListNode* list = NULL;
ListNode* pos;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,2);
PushFront(&list,1);
PrintList(list);
/*pos = Find(list,1);
Insert(&list,pos,0);
PrintList(list);*/
/*pos = Find(list,1);
Insert(&list,pos,0);
PrintList(list);*/
pos = Find(list,3);//找不到时返回NULL,则变成了尾插
Insert(&list,pos,0);
PrintList(list);
Erase(&list,pos);
PrintList(list);
}
void test4()
{
ListNode* list = NULL;
ListNode* pos;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,2);
PushFront(&list,1);
PrintTailToHead(list);
printf("\n");
/*pos = Find(list,2);
EraseNonTail(pos);
PrintList(list);*/
pos = Find(list,4);//非尾节点,而4是尾节点
EraseNonTail(pos);
PrintList(list);
}
void test5()
{
ListNode* list = NULL;
ListNode* pos;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,1);
PrintList(list);
pos = Find(list,3);
InsertNonHead(pos,2);
PrintList(list);
}
void test6()
{
ListNode* list = NULL;
ListNode* tail ;
ListNode* man;
PushBack(&list,1);
PushBack(&list,2);
PushBack(&list,3);
PushBack(&list,4);
PushBack(&list,5);
PushBack(&list,6);
PushBack(&list,7);
PushBack(&list,8);
PrintList(list);
tail = Find(list,8);
tail->next = list;
man = JosepRing(list,3);
printf("幸存者:%d \n",man->data);
}
void test7()
{
ListNode* list = NULL;
PushFront(&list,6);
PushFront(&list,4);
PushFront(&list,8);
PushFront(&list,1);
PrintList(list);
//Reverse(&list);
SortList(list);
PrintList(list);
}
void test8()
{
ListNode* list1 = NULL;
ListNode* list2 = NULL;
ListNode* list = NULL;
//ListNode* mid;
PushBack(&list1,1);
PushBack(&list1,2);
PushBack(&list1,5);
PushBack(&list1,7);
PrintList(list1);
PushBack(&list2,3);
PushBack(&list2,4);
PushBack(&list2,8);
PushBack(&list2,9);
PrintList(list2);
list = Merge(list1,list2);
PrintList(list);
}
void test9()
{
ListNode* list = NULL;
ListNode* mid;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,2);
PushFront(&list,1);
PrintList(list);
mid = FindMidNode(list);
printf("中间节点是%d\n",mid->data);
FindKNode(list,2);
PrintList(list);
}
void test10()
{
ListNode* list = NULL;
ListNode* tail;
ListNode* entry;//入口点
ListNode* meet;//相遇点
int length ;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
PushBack(&list, 6);
PrintList(list);
tail = Find(list, 6);
entry = Find(list, 4);
tail->next = entry;//带环
meet = IsCycle(list);
printf("入口点:%d\n", GetEntry(list, meet)->data);
length = GetCycle_Length(meet);
printf("环的长度为%d\n",length);
}
void test11()
{
ListNode* cross, *tail;
ListNode* list1 = NULL;
ListNode* list2 = NULL;
PushBack(&list1, 1);
PushBack(&list1, 2);
PushBack(&list1, 3);
PrintList(list1);
PushBack(&list2, 4);
PushBack(&list2, 5);
PushBack(&list2, 6);
PushBack(&list2, 7);
PushBack(&list2, 8);
PushBack(&list2, 9);
PrintList(list2);
cross = Find(list2, 8);
tail = Find(list1, 3);
tail->next = cross;
//判断两个链表是否相交?
if( 1 == IsCross_NoCycle(list1,list2) )
printf("两个链表相交,");
//求交点
printf("交点是:%d\n", GetCrossNode(list1, list2)->data);
}
void test12()//判断两个链表是否相交?相同的入口点
{
ListNode* cross, *tail1,*tail2;
ListNode* entry;
ListNode* list1 = NULL;
ListNode* list2 = NULL;
ListNode* meet;
PushBack(&list1, 1);
PushBack(&list1, 2);
PushBack(&list1, 3);
PrintList(list1);
PushBack(&list2, 4);
PushBack(&list2, 5);
PushBack(&list2, 6);
PushBack(&list2, 7);
PushBack(&list2, 8);
PushBack(&list2, 9);
PushBack(&list2, 10);
PushBack(&list2, 11);
PrintList(list2);
cross = Find(list2, 8);//交点
tail1 = Find(list1, 3);
tail1->next = cross;
tail2 = Find(list2, 11);
entry = Find(list2, 9);//入口点
tail2->next = entry;//带环
meet = IsCross_Cycle(list1,list2);
printf("交点是:%d\n",meet->data);
}
int main()
{
//test1();//尾插 尾删
//test2();//尾插 尾删
//test3();//查找K pos前插入节点 删除pos节点
//test4();//2.从尾到头打印单链表 3.删除一个无头单链表的非尾节点
//test5();//4.在无头单链表的一个节点前插入一个节点
//test6();//5.单链表实现约瑟夫环
//test7();//6.翻转/逆置链表 7.单链表排序(冒泡排序)
//test8();//8.合并两个有序单链表,合并后依然有序
//test9();//9.查找链表的中间节点,要求只能遍历一次 10.查找单链表的倒数第k个节点,要求只能遍历一次
//test10();//11.判断单链表是否带环?若带环,求环的入口点;若带环,求环的长度
//test11();//12.判断两个链表是否相交?若相交,求交点(假设链表不带环)
test12();//13.判断两个链表是否相交?若相交,求交点。(假设链表可能带环)
return 0;
}