判断一个单链表是否有环及环的链接点

来源:互联网 发布:php语言能做大型项目吗 编辑:程序博客网 时间:2024/04/29 10:41

给定一个单链表,只给出头指针h:

1、如何判断是否存在环?

2、如何知道环的长度?

3、如何找出环的连接点在哪里?

4、带环链表的长度是多少?

1、对于问题1,使用追赶的方法,设定两个指针ps、pf,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,pf遇到NULL退出。

证明:如果存在环,则他俩一定在环中相遇。

设i是走的步数,n是环的长度,

从ps走进环里开始计算,此时pf应当有一个相距于ps的距离,设为Y。

假设走了i步他俩相遇,此时ps相对于环开始节点的距离是i步,pf是Y+2i步。

相遇时快指针多走了一圈 (Y+2i)-i= n => Y+i=n =>i=n-y

所以,追上的步数i取决于进入环时y的值。y是1的时候,是追的最费劲的,需要n-1步;y是n-1的时候最容易追,1步就追上了。

Boolean has_loop(Node *head) {  Node *pf = head; /* fast pointer */  Node *ps = head; /* slow pointer */  while(true) {    if(pf && pf->next)      pf = pf->next->next;    else      return FALSE;    ps = ps->next;    if(ps == pf)      return TRUE;  }}
2、对于问题2,记录下问题1的碰撞点p,ps、pf从该点开始,再次碰撞所走过的操作数就是环的长度n。

证明:上面的公式i=n-y,当y=0时,就是第一次相遇时开始走,i=n。

/* step 2, how long is the loop */  int i = 0;   do {    ps = ps->next;    pf = pf->next->next;    i++;  } while(ps!=pf)

3.假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为n,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x距离),得到以下关系:
    s = a + x;
    2s = a + nr + x;
    =>a + x = nr;
    =>x = nr - a;
逆时针方向走,pf还需要走的距离是y,

y+x=tn

=>y+nr-a=tn=>y=(t-r)n+a//y的距离就是a又加了几圈

由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点,搞掂!


int FindLoopPort(Node *head) {  Node *pf = head; /* fast pointer */  Node *ps = head; /* slow pointer */  while(true) {    if(pf && pf->next)      pf = pf->next->next;    else      return FALSE;    ps = ps->next;    if(ps == pf)      break;  }  pf = head;  int i = 0;  while(ps != pf)  {ps = ps->next;pf = pf->next;i++;  }  return i;}

4. 将2和3的长度相加就是链表的长度。




0 0
原创粉丝点击