今天来说一下判断两个无头结点的单链表是否相交的代码,
无头结点的单链表自身分为两种情况,带环和不带环,
l1,l2分别代表两条链表,
用真值表来表示,1表示带环,0表示不带环
l1 | l2 |
0 | 0 |
0 | 1 |
1 | 0 |
1 | 1 |
首先我们来讨论一下较为简单的不带环的情况:
如图所示,共有两种情况,即相交和不相交。
相交分为三种情况(可以视为一条链表的尾部分别和另一条链表的不同部分相交):即头部、中间和尾部。
由图我们可以看出,若两条链表相交,他们的尾结点一定相同。
这可以作为我们判断两结点是否相交的判断点。
代码实现如下:
// 判断两个单链表是否相交---链表不带环
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)//pHead1代表链表1,pHead2代表链表2
{
PNode pTail1 = pHead1;//定义链表1的尾结点,并让其指向链表1的头结点
PNode pTail2 = pHead2;//定义链表2的尾结点,并让其指向链表2的头结点
//两链表只要有一个为空即不相交
if (NULL == pTail1 || NULL == pTail2)
{
return 0;
}
//遍历链表1,找到尾结点
while (pTail1->_pNext)
{
pTail1 = pTail1->_pNext;
}
//遍历链表2,找到尾结点
while (pTail2->_pNext)
{
pTail2 = pTail2->_pNext;
}
//判断两条链表的尾结点是否相等
if (pTail1 == pTail2)
{
return 1;//相等即相交,返回1
}
return 0;//不相等即不相交,返回0
}
构建的两条链表如下:
//构建两条链表
PNode pHead1;
PNode pHead2;
SListInit(&pHead1);//链表初始化
SListPushBack(&pHead1, 1);//链表尾插
SListPushBack(&pHead1, 2);
SListPushBack(&pHead1, 3);
SListInit(&pHead2);
SListPushBack(&pHead2, 1);
SListPushBack(&pHead2, 2);
SListPushBack(&pHead2, 3);
while (pHead1->_pNext)
{
pHead1 = pHead1->_pNext;
}
pHead1->_pNext = pHead2;
该种情况为相交的第三种情况,测试结果如下:
输出1,则其相交,其他情况不再一一描述。
带环的情况也比较多,不过经过分析也不会那么复杂。
接下来我们来画图进行分析
由图我们可以得知,两个带环的链表相交分为,环内相交和环外相交两种。
在判断两链表是否相交的过程中,我们还需要实现判断链表是否带环,
判断链表是否带环:
1、定义两个指针,一个一次走两个结点(pFast),一个一次走一个结点(pSlow)
2、若有环,pFast会与pSlow相遇,此时返回两指针的地址;
若无环,如果pFast==NULL,即可证明其无环,返回空指针
代码实现如下:
PNode IsListwithCircle(PNode pHead)
{
PNode pFast = pHead;
PNode pSlow = pHead;
if (NULL == pHead)
{
return NULL;
}
while (pFast->_pNext)
{
pFast = pFast->_pNext->_pNext;
pSlow = pSlow->_pNext;
if (pFast == pSlow)
return pFast;
}
return NULL;
}
接着判断两个链表是否相交:
大概思路就是:让两个链表的相遇点一个保持不动,一个往后走(每次走一步),若两个相遇点相遇,即可说明两条链表相交。
代码实现如下:
int IsCrossWithCircle(PNode pHead1, PNode pHead2)
{
PNode pMeetNode1 = NULL;
PNode pMeetNode2 = NULL;
PNode pCur = NULL;
if (NULL == pHead1 || NULL == pHead2)
{
return 0;
}
pMeetNode1 = IsListwithCircle(pHead1);
pMeetNode2 = IsListwithCircle(pHead2);
pCur = pMeetNode1;
//其中一个链表带环或两条链表均不带环
if (NULL == pMeetNode1 || NULL == pMeetNode2)
return 0;
//两条链表均带环
while (pMeetNode1 != pMeetNode2)
{
pCur = pCur->_pNext;
if (pCur == pMeetNode1)
return 0;
}
return 1;
}
关于测试结果就不在展示了
判断两条链表是否相交经常会出现在面试题中,如果把图画出来写程序会更有思路。
欢迎交流~