在單鏈表的衆多問題中,其中單鏈表的相交問題就佔了比較多的成分,在鏈表中分帶環相交,不帶環相交等等。。
所以我們先從不帶環的單鏈表說起;
兩個不帶環的單鏈表
判斷兩個單鏈表是否相交???
在這個問題中,我們得先分清情況,下面我用圖畫出來:
其實很見到就只有這兩中情況,沒有大家想的那麼複雜:
int IsListCross(PNode L1, PNode L2)// 判斷兩個單鏈表是否相交(鏈表不帶環) 只有兩種情況
{
PNode pL1 = L1;
PNode pL2 = L2;
if (NULL == pL1 || NULL == pL2)
return 0;
while (pL1->_pNext)
pL1 = pL1->_pNext;
while (pL2->_pNext)
pL2 = pL2->_pNext;
if (pL1 == pL2)
return 1;
return 0;
}
若不帶環的單鏈表相交,求交點???
我們已經知道了它就只有這兩種情況,我們可以直接遍歷兩條單鏈表把長的先走完,然後讓他們兩個同時走,當兩個鏈表結點相同時就是交點了
PNode GetCrossNode(PNode PL1, PNode PL2)// 若不帶環的單鏈表相交,求交點
{
int count1 = 1;
int count2 = 1;
int tmp = 0;
PNode pL1 = PL1;
PNode pL2 = PL2;
if (pL1 == NULL || pL2 == NULL)
return 0;
while (pL1->_pNext)
{
pL1 = pL1->_pNext;
++count1;
}
while (pL2->_pNext)
{
pL2 = pL2->_pNext;
++count2;
}
pL1 = PL1;
pL2 = PL2;
if (count1 - count2 >= 0)
{
tmp = count1 - count2;
while (tmp--)
pL1 = pL1->_pNext;
}
else
{
tmp = count2 - count1;
while (tmp--)
pL2 = pL2->_pNext;
}
while (pL1->_pNext)
{
if (pL1 == pL2)
break;
else
{
pL1 = pL1->_pNext;
pL2 = pL2->_pNext;
}
}
if (pL1 == pL2)
return pL1;
return NULL;
}
簡單的不帶環的解決了,下面就來點有難度的帶環的(其實也不難)
兩個帶環的單鏈表
判斷鏈表是否帶環,若帶環給出相遇點;
在這道題中,如果有環,我們可以想到有兩個結點,一個走快點一個走慢點,走得快的人一直在環裏繞,那麼慢的人一定會和快的人相遇,沒環兩個人永遠都不可能相遇(除了頭結點)
PNode HasCircle(PNode pHead)// 判斷鏈表是否帶環,若帶環給出相遇點
{
PNode FastNode = pHead;
PNode SlowNode = pHead;
if (NULL == FastNode || NULL == FastNode->_pNext)
return NULL;
while (FastNode != NULL && FastNode->_pNext != NULL)
{
FastNode = FastNode->_pNext->_pNext;
SlowNode = SlowNode->_pNext;
if (FastNode == SlowNode)//有環
return SlowNode;
}
return NULL;
}
求環的長度
既然我們在上面已經知道了它有環,並且知道了相遇點,那麼從相遇點走一圈就是環的長度了
size_t GetCircleLen(PNode pMeetNode)// 求環的長度
{
int count = 1;//注意
PNode pPreNode = pMeetNode;
while (pPreNode->_pNext != pMeetNode)
{
pPreNode = pPreNode->_pNext;
++count;
}
return count;
}
注意上段代碼中,我寫注意的地方哪裏不小心就是坑,我們從相遇點開始找,但是循環結束的條件是某個節點的下一個結點是相遇點就不進入循環,那麼相遇點的上一節點我們沒有加進來啊,所以count是從1開始加的;
求環的入口點
所以我們從圖中的文字和圖示大概能明白怎麼計算:
PNode GetEnterNode(PNode pHead, PNode pMeetNode)// 求環的入口點
{
PNode Enter = pHead;
while (Enter != pMeetNode)
{
Enter = Enter->_pNext;
pMeetNode = pMeetNode->_pNext;
}
return Enter;
}
上面每段代碼我只是給瞭解決問題的部分代碼,如果對基本操作有點問題或者對它的構環有點不明白,可以去看看github
單鏈表的頭文件單鏈表的基本操作
構環可以參考我的單鏈表實現約瑟夫環