确定链表环的长度与入口,以及算法的正确性分析

在之前的文章里偶分析了追赶法判断链表是否有环(叫龟兔赛跑法可能会更贴切)算法的正确性。但是还有几个问题必须解决:
1. 环的长度
2. 环的入口

3.整个链表的长度
第一个问题很好解决,因为龟兔二人第一次相遇的点(不放设为k)必然在环内,这时再以相遇点作为起点,新定义一向量向前移动,直到移动到自身为止,移动的步数就是环的长度,这个很好理解。
第二个问题稍微要思考一下,如果使用标记法,这个问题很好解决,但是在追赶法中我们需要看看这个入口位置和相遇点k有什麽关系。
给出带头的单链如下所示:
H->1->2->3->4->5->6->7-8->9
长度n=9
环的入口点设在a=6处
很明显环的长度就是n-a+1
则由相遇的步数公式k=d*(n-a+1)直到第一个k=8
我们发现从k处走到a处的步数y符合公式y=d2*(n-a+1)+(n-k+1)的形式,其中d2是正整数(>=0),这个很好理解,要麽d2=0,从8走到9再走到6就是3步=n-k+1,或者d2>0,再多走一圈。
而k=d*(n-a+1),由此代入上式得:y=(d2-d)(n-a+1)+n+1;
令d2-d=-1,则y=a;这是神麽意思涅?没错,这意味着只要令d2比d小1,这时候从k走到a的步数恰好就等于a在链表中所处的位置,也即使从链表头走到a的步数。
所以我们用两个游标(指针)就可以完成环入口点的挖掘,一个游标从链表头移动,一个游标从k移动,它们两移动了a步之后恰好在a位置相遇!

 

第三个问题呢:

基于前两个问题,这个问题再简单不过了,n-a+1环的长度我们已知了,a环的入口点我们已知了,n还能不知嘛?
话不多说,给出代码(不含第三个问题):

 

 

   1:  /*
   2:  check if have loop, and caculate the step to find the loop, the length of loop, the entry point of loop
   3:  */
   4:  int check_loop3(pnode list,int *stepCount,int *lengthOfLoop,int *startIndexOfLoop)
   5:  {
   6:      pnode p1=list;
   7:      pnode p2=list;
   8:      if(p1==p2->next)
   9:      {
  10:          *stepCount=1;
  11:          *lengthOfLoop=1;
  12:          *startIndexOfLoop=0;
  13:          return 1;
  14:      }
  15:   
  16:      while(p1->next!=NULL && p2->next!=NULL)
  17:      {
  18:          (*stepCount)++;
  19:          p1=p1->next;
  20:          p2=p2->next->next;
  21:          if(p1==p2)
  22:          {
  23:              *lengthOfLoop=get_loop_length(p1);
  24:              *startIndexOfLoop=get_startindex_of_loop(list,p1);
  25:              return 1;
  26:          }
  27:      }
  28:   
  29:   
  30:      //if not fount, reset the count
  31:      stepCount=0;
  32:      lengthOfLoop=0;
  33:      startIndexOfLoop=0;
  34:      return 0;
  35:  }
  36:   
  37:  /*
  38:  find the entry point of loop
  39:  assume the loop already exist
  40:  */
  41:  int get_startindex_of_loop(pnode list,pnode thek)
  42:  {
  43:      int index=0;
  44:      pnode p1=list;
  45:      pnode p2=thek;
  46:   
  47:      while(p1!=NULL && p2!=NULL)
  48:      {
  49:          if(p1==p2)
  50:          {
  51:              return index;
  52:          }
  53:          p1=p1->next;
  54:          p2=p2->next;
  55:          index++;
  56:      }
  57:   
  58:      return -1;
  59:  }
  60:   
  61:  /*
  62:  find the loop length
  63:  assume the loop already exist,or will never stop loop
  64:  */
  65:  int get_loop_length(pnode thek)
  66:  {
  67:      int len=0;
  68:      pnode p=thek->next;
  69:      len++;
  70:      while(p!=thek)
  71:      {
  72:          p=p->next;
  73:          len++;
  74:      }
  75:      return len;
  76:  }

 

 

TEST:

   1:   
   2:  int main()
   3:  {
   4:      int i=0;
   5:      pnode list=create_newnode();
   6:      pnode p;
   7:      for(i=1;i<10;i++)
   8:      {
   9:          p=create_newnode();
  10:          p->value=i;
  11:          append(list,p);
  12:      }
  13:      p->next=list->next->next->next->next->next->next;
  14:      //list->next->next=list;
  15:      //list->next->next=list;
  16:   
  17:      int x=0;
  18:      int y=0;
  19:      int z=0;
  20:      int r=check_loop3(list,&x,&y,&z);
  21:   
  22:      printf("%d,%d,%d,%d",r,x,y,z);
  23:      return 0;
  24:  }
posted @ 2012-07-07 10:54  Dance With Automation  Views(468)  Comments(0)    收藏  举报