- 判断单链表是否带环?若带环,求环的长度?求环的入口点?
判断是否带环:要判断链表有没有带环,不能按常理去判断最后一个节点的next是否为空,因为带环链表找不到最后一个节点。需借助快慢指针来解决。定义fast指针每次走两步,slow指针每次走一步,这样fast指针和slow指针如果在环里相遇,就可以断定有环,否则无环。
ListNode* Is_Loop_List(ListNode* pList)//是否带环,并返回相遇点
{
if (pList == NULL)
{
return NULL;
}
ListNode* fast = pList;
ListNode* slow = pList;
while (fast->next && fast)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return slow;
}
}
return NULL;
}
这里就出现了新问题:fast指针可以一次走三步,走四步……吗???
答案肯定是不能。因为fast每次走两步,slow每次走一步,快慢指针每次缩小的距离是一步,不会出现错过或者跳过的情况。而如果fast指针一次走三步,四步,会出现跳过的情况。
求环的长度:根据快慢指针相遇点,从相遇点的next开始遍历,当遇到相遇点停止,count进行计数,count值即为环的长度。
int Length_Loop(ListNode* pList)//求环的长度
{
ListNode* meethead = Is_Loop_List(pList);
while (meethead)
{
ListNode* prev = meethead->next;
int count = 1;
while (prev != meethead)
{
count++;
prev = prev->next;
}
return count;
}
return 0;
}
求环的入口点:
上图可知:从环头节点和相遇点遍历节点,会在某个节点处相遇,这个节点就是环入口点。
ListNode* Enter_Node(ListNode* pList)//求环的入口点
{
ListNode* meethead = Is_Loop_List(pList);
while (meethead)
{
while (pList != meethead)
{
pList = pList->next;
meethead = meethead->next;
}
return pList;
}
return NULL;
}
2.判断两个不带环链表是否相交,若相交,求交点。
先举例看一下何为相交链表
1>,先分别求出两个链表的长度,求出长度差;
2>,让长链表先走长度差的距离,接着短链表和长链表一起走;
3>,当出现节点数值一样时,那么相交点就找到了。
int Check_cross(ListNode* pList1, ListNode* pList2)//是否相交
{
if (pList1 == NULL || pList2 == NULL)
{
return 0;
}
ListNode* prev1 = pList1;
ListNode* prev2 = pList2;
while(prev1->next)
{
prev1 = prev1->next;
}
while ( prev2->next)
{
prev2 = prev2->next;
}
if (prev1->data == prev2->data)
{
return 1;
}
return 0;
}
int Length_List(ListNode* pList)//求链表长度
{
if (pList == NULL)
{
return 0;
}
int count = 1;
while (pList->next)
{
count++;
pList = pList->next;
}
return count;
}
ListNode* List_Intersection(ListNode* pList1, ListNode* pList2)//求链表的交点
{
int Len1 = Length_List(pList1);
int Len2 = Length_List(pList2);
ListNode* longlist = pList1;
ListNode* shortlist = pList2;
if (Len1 < Len2)
{
longlist = pList2;
shortlist = pList1;
}
int tmp = abs(Len1-Len2);
while (tmp--)
{
longlist = longlist->next;
}
while (longlist)
{
if (longlist->data == shortlist->data)
{
return longlist;
}
shortlist = shortlist->next;
longlist = longlist->next;
}
return NULL;
}
3,判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
分为以下几种情况:
ListNode* List_loop_cross(ListNode* pList1, ListNode* pList2)
{
if (pList1 == NULL || pList2 == NULL)
{
return NULL;
}
ListNode* enter1 = Enter_Node(pList1);//入口点
ListNode* enter2 = Enter_Node(pList2);
if (enter1 == NULL && enter2 == NULL)//两个链表的入口点为空,不带环 判断有无交点
{
return List_Intersection(pList1, pList2);
}
else if ((enter1 != NULL&&enter2 == NULL) ||
(enter1 == NULL&&enter2 != NULL))//一个链表有环,一个链表无环,不相交
{
return NULL;
}
else if (enter1 == enter2)//入口点相等
{
enter1->next = NULL;
enter2->next = NULL;//去掉环之后,按无环处理
return List_Intersection(pList1, pList2);
}
else//一个环上有两个入口点
{
ListNode* cur = enter1->next;
while (cur != enter1)
{
if (cur == enter2)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
}
4.求两个已排序单链表中相同的数据
1>,当两个节点数值相等时,尾插到新建链表上,并同时向后走一步;
2>,当两个数不相等时,数值小的节点向后走一步,数值大的节点不动,继续进行比较,直到任意链表为空。
ListNode* Union_Node(ListNode* List1, ListNode* List2)
{
ListNode* newlist = NULL;
ListNode* cur = List1;
ListNode* prev = List2;
while (cur && prev)
{
if (cur->data == prev->data)
{
PushBack(&newlist, cur->data);
cur = cur->next;
prev = prev->next;
}
else if (cur->data > prev->data)
{
prev = prev->next;
}
else
{
cur = cur->next;
}
}
return newlist;
}