在单链表的众多问题中,其中单链表的相交问题就占了比较多的成分,在链表中分带环相交,不带环相交等等。。
所以我们先从不带环的单链表说起;
两个不带环的单链表
判断两个单链表是否相交???
在这个问题中,我们得先分清情况,下面我用图画出来:
其实很见到就只有这两中情况,没有大家想的那么复杂:
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
单链表的头文件单链表的基本操作
构环可以参考我的单链表实现约瑟夫环