1.【基础题】–1.判断两个链表是否相交,若相交,求交点。(假设链表不带环)2.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
2.【附加题】–请问下面的程序一共输出多少个“-”?
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int i;
for(i=0; i<2; i++){
fork();
printf("-");
}
return 0;
}
**
基础题:
**
定义的单链表节点
#include <iostream> //采用C++编译环境。
typedef struct ListNode
{
int _val;
ListNode* _pNext;
}Node, *PNode;
在代码中定义的一些函数
//获取环中节点中快慢指针的碰撞点。
PNode Get_Impact_Point(PNode pHead);
//获取带环链表中环的入口点
PNode Get_Entrance_Point(PNode pHead);
//判断两个链表是否相交,若相交,求交点。(假设链表不带环)
PNode Is_Has_Intersection(PNode pHead_1, PNode pHead_2);
//判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
PNode Is_Has_Intersection_2(PNode pHead_1, PNode pHead_2);
1.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
思路:
不带环的两个链表相交,表示从交节点开始,两个链表中的节点一直相同。
那么两个链表的最后一个节点也相同。可以当做一个判断条件。
如果两个不带环链表相交,则将其中一个链表的头尾节点相连,构成一个带环的单链表。
这样问题就变为了,求带环单链表的环的入口点的问题。
PNode Is_Has_Intersection(PNode pHead_1, PNode pHead_2)
{
if ((NULL == pHead_1) || (NULL == pHead_2)) //当有空链表时,没有交点。
return NULL;
if (pHead_1 == pHead_2) //如果两个链表是通过一个链表的情况。
return pHead_1;
PNode pTail_1 = pHead_1; //用来指向pHead_1的尾节点
PNode pTail_2 = pHead_2; //用来指向pHead_2的尾节点
while (pTail_1->_pNext)
pTail_1 = pTail_1->_pNext;
while (pTail_2->_pNext)
pTail_2 = pTail_2->_pNext;
if (pTail_1 != pTail_2) //两个链表最后一个节点不相等,说明没有相交。
return NULL;
//走到这里,说明pTail_1 = pTail_2。两个链表相交,下面开始求交点。
//将其中一个链表的头结点与尾节点相连。最终两个链表会构成一带环单链表
//问题变为求带环单链表的环的入口了。
//1,将两个单链表变为带环单链表(pHead_2为新的头指针)
pTail_1->_pNext = pHead_1;
//2,求环的入口。(调用写的函数,前一篇博文已写,后面也会给出)
PNode pCross = Get_Entrance_Point(pHead_2);
return pCross;
}
2.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
思路:
先判断两个链表是否是同一个链表的情况。
1,相同,直接返回头结点。
2,不相同,在往下走。
再判断两个链表是否带环。
1,都不带环—>判断两个不带环单链表是否相交,若相交,求交点。
2,一个带环,一个不带环—->不想交
3,两个链表都带环—->1,交点在环外,2,交点再环内,3,不相交
通过两个链表环的入口点是否相等,来判断交点在环外还是环内。
若相等,则在环外或者就是入口点处。此时相交。–》去掉环,变为求两个不带环单链表求交点交点
若不相等,则判断两个入口点是否在通过一个环中,若在环中,则两个入口点都是交点。否则,不相交。
PNode Is_Has_Intersection_2(PNode pHead_1, PNode pHead_2)
{
//存在空链表,不存在交点
if ((NULL == pHead_1) || (NULL == pHead_2))
return NULL;
//如果两个链表是同一个链表,则直接返回头结点。
if (pHead_1 == pHead_2)
return pHead_1;
PNode pCross = NULL; //交点
//获取链表快慢指针的碰撞点,如果存在,则说明链表有环
PNode pImpact_1 = Get_Impact_Point(pHead_1);
PNode pImpact_2 = Get_Impact_Point(pHead_2);
//都不带环--->判断两个不带环单链表是否相交,若相交,求交点。
if ((NULL == pImpact_1) && (NULL == pImpact_2))
{
pCross = Is_Has_Intersection(pHead_1, pHead_2);
return pCross;
}
//一个带环,一个不带环---->不相交
if (!pImpact_1 || !pImpact_2)
return NULL;
//两个链表都带环---->若相交,环是公有的,则判断链表1的碰撞点是否在链表2的环中
//两个链表都带环的情况。
//有三种情况。
//1,不相交。
//2,相交,交点在环外。
//3,相交,交点在环内。
//为了不重复定义变量,浪费空间,暂时用pImpact指向返回的环入口点。
pImpact_1 = Get_Entrance_Point(pHead_1);
pImpact_2 = Get_Entrance_Point(pHead_2);
//此时,带环链表有可能相交于环内,有可能不相交
if (pImpact_1 != pImpact_2)
{
PNode pCur = pImpact_2; //作为遍历pHead_2的指针
//需要注意的是,在遍历pHead_2时,如果pHead_1的入口点不在pHead_2的环中,会死循环
//所以,需要从pHead_2的环入口点,开始遍历,直到再次遇到入口点。
while (pCur != pImpact_1)
{
pCur = pCur->_pNext;
if (pCur == pImpact_2) //防止在环内一直遍历,而死循环
break;
}
//pHead_1的入口点pImpact_1在pHead_2的环中,即相交,随便返回一个入口点
if (pCur == pImpact_1)
{
return pImpact_1;
}
else //否则,不相交
{
return NULL;
}
}
//pImpact_1 == pImpact_2
//此时,两个链表有一个公共环,并且,节点在环外。--》去掉环的影响,变为求两个不带环单链表求交点问题
PNode pTemp = pImpact_1->_pNext; //记录,环的入口的下一节点。
pImpact_1->_pNext = pHead_1; //去掉旧环,构成一个新环(pHead_2为头结点)
//获取新环的入口点,即原来两个链表的交点
pCross = Get_Entrance_Point(pHead_2);
//去掉新环,还原旧环
pImpact_1->_pNext = pTemp;
return pCross;
}
3.下面给出上述两个函数中调用的自定义函数
//获取环中节点中快慢指针的碰撞点。
PNode Get_Impact_Point(PNode pHead)
{
if (NULL == pHead)
return NULL;
PNode pFast = pHead; //快指针每次走两步
PNode pSlow = pHead; //慢指针每次走一步
while ((NULL != pFast) && (NULL != pFast->_pNext))
{
pFast = pFast->_pNext->_pNext;
pSlow = pSlow->_pNext;
if (pFast == pSlow)
break;
}
if ((NULL == pFast) || (NULL == pFast->_pNext)) //不可使用pFast!=pSlow作为判断条件,当链表只有一个元素时,会出错。
return NULL;
return pFast;
}
//获取带环链表中环的入口点
PNode Get_Entrance_Point(PNode pHead)
{
PNode pImpact = Get_Impact_Point(pHead);
if (NULL == pImpact) //链表中不存在环
return NULL;
//头结点到入口点的长度设为:X
//环的长度设为R
//碰撞点到入口的长度设为:R1
//通过计算(前一篇博文中写有),可以推到出存在某一个n(n为非负整数),使得:X = nR + R1.
//所以,头结点和碰撞点同时出发, 最终会在入口点相遇。
while (pImpact != pHead)
{
pImpact = pImpact->_pNext;
pHead = pHead->_pNext;
}
//此时,两者都在入口点处,返回入口点位置。
return pImpact;
}
**
附加题
**
关于fork函数的知识,推荐博文:http://blog.youkuaiyun.com/jason314/article/details/5640969
里面对于fork进行了深入的讲解。而且例子也比较好。也包括这个例子。
下面,呈现在ubuntu下运行的结果图。
li
结果打印了6个‘-’