单链表相关的博客:
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/80458397
单链表带环问题
- 解决方法:快慢指针
1.判断单链表是否带环?若带环,求环的入口点?若带环,求环的长度?
2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
1.判断单链表是否带环?若带环,求环的入口点?
- 如何求环的入口点:
- 如何求环的长度:
思想:从相遇点开始遍历链表,一直走到和相遇点相等的地方,便是一个环的长度。
代码实现:
ListNode* IsCycle(ListNode* plist)//判断链表是否带环?
{
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;
}
void test()
{
ListNode* list = NULL;
ListNode* tail;
ListNode* entry;//入口点
ListNode* meet;//相遇点
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
PushBack(&list, 6);
PrintList(list);
tail = Find(list, 6);
enrty = Find(list, 4);
tail->next = entry;//带环
meet = IsCycle(list);
printf("入口点:%d\n", GetEntry(list, meet)->data);
length = GetCycle_Length(meet);
printf("环的长度为%d\n",length);
}
2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
- 判断两个链表是否相交?:
- 若相交,求交点:
代码实现:
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;
}
void test()
{
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);
}
3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
代码实现:
ListNode* IsCross_Cycle(ListNode* plist1,ListNode* plist2)
{
//求链表带环的相遇点
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;//不相交
}
void test()//判断两个链表是否相交?相同的入口点
{
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);
}