6-3 尾部循环的单链表

正是老师上课讲的关于“一只兔子撞到猎人粗壮的大腿上”的问题:

一个本来不循环的单链表,当我们把它的tail上的NULL指针改成指向链表中的某一结点时,这张单链表就会在一部分结点上产生循环,就像这样:

我们可以先试着把循环部分的长度求出来,然后再想办法把循环部分最靠前的结点给定位出来(也就是题目要求的)。

把循环部分最靠前的结点记作 第桩子个结点。

从head放出一只兔子和一只乌龟,兔子会比乌龟先进入循环,因为他们有速度差,所以一定会相遇。假设兔子还没走第二个循环就遇到了乌龟,我们可以得到循环体长度Cycle。

把动点1放在head,把动点2放在第Cycle个结点。 因为Cycle+ 桩子= 总的结点个数。所以,此时,动点2向后走桩子个结点,就会返回到桩子结点了。我们让两个点以相同的速度开始走,比较他们的地址来判断动点2是不是返回来了。

我以这样的思路写了代码,在写这篇文章时意识到事实上Cycle并不总是循环体长度,而是循环体长度的n倍,因为我们不能总是假设一定会在兔子走入第二个循环前与乌龟相遇。然而这一点并不会影响程序的功能,在定位部分总是精确的,也就是不论如何,把动点2放在第Cycle个结点,那么再走桩子个结点,一定能返回来。这一点或许可以严谨地证明一下。

int find_cycling_position(Node* head){
struct Node* rbt= head->next;
struct Node* tut= head;
int i=0, j=0;
int cycle=0;

//求圈长的代码被省略了
//tips: 我们用地址的一致来定义相遇


//定位
struct Node *fst, *snd;
snd= fst= head;
for(int k=0; k<=cycle; k++){
	fst= fst->next; 
}

int p=1;
for(; snd!=fst; p++, snd=snd->next, fst=fst->next);


return p;
}

猜你喜欢

转载自blog.csdn.net/roswellnotfound/article/details/108552028
6-3