在之前的文章里偶分析了追赶法判断链表是否有环(叫龟兔赛跑法可能会更贴切)算法的正确性。但是还有几个问题必须解决:
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: }