理论:
(来自网络,但原创已经无法追溯,一转载链接如下:http://blog.csdn.net/wuzhekai1985/article/details/6725263)
若存在环,如何找到环的入口点(即上图中的结点E)?
解答:如图中所示,设链起点到环入口点间的距离为x,环入口点到fast与low重合点的距离为y,又设在fast与low重合时fast已绕环n周(n>0),且此时low移动总长度为s,则fast移动总长度为2s,环的长度为r。则
s + nr = 2s,n>0 ①
s = x + y ②
由①式得 s = nr
代入②式得
nr = x + y
x = nr - y ③
现让一指针p从链表起点处开始遍历,指针q从encounter处开始遍历,且p和q移动步长均为1。则当p移动x步即到达环的入口点,由③式可知,此时q也已移动x步即nr - y步。由于q是从encounter处开始移动,故q移动nr步是移回到了encounter处,再退y步则是到了环的入口点。也即,当p1移动x步第一次到达环的入口点时,p2也恰好到达了该入口点。
无代码无真相
恳请各位指正批评。
#include "list.h"
plist encounter(plist head)
{
plist fast, slow;
if(head == NULL)
{
printf("list error\n");
return 0;
}
fast = slow = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
{
return fast;
}
}
return NULL;
}
plist get_encounter_node(plist head)
{
plist p, q;
p = head;
q = encounter(head);
if(q != NULL)
{
while(p != q)
{
p = p->next;
q = q->next;
}
}
return q;
}
int main()
{
int i;
plist head;
plist p, q;
plist new;
plist enc;
head = init_list();
for(i = 0; i < 4; i++)
{
tail_insert(head, i);
}
p = head;
while(p->next != NULL)
{
p = p->next;
}
//
//create ring node
new = (plist)malloc(sizeof(list));
if(new == NULL)
{
printf("malloc error in %s line %d\n", __FUNCTION__, __LINE__);
}
new->data = 111;
new->next = p->next;
p->next = new;
p = new;
for(i = 0; i < 4; i++)
{
q = (plist)malloc(sizeof(list));
if(new == NULL)
{
printf("malloc error in %s line %d\n", __FUNCTION__, __LINE__);
}
q->data = 2*i+1;
q->next = p->next;
p->next = q;
p = q;
}
q->next = new;
/
enc = get_encounter_node(head);
if(enc != NULL)
{
printf("Entry node is %d\n", enc->data);
}
else
{
printf("No ring\n");
}
free_ring_list(head, enc);
return 0;
}
#ifndef _LIST_H_
#define _LIST_H_
#include <stdio.h>
#include <stdlib.h>
struct list
{
int data;
struct list *next;
};
typedef struct list list;
typedef struct list *plist;
plist init_list()
{
plist head;
head = (plist)malloc(sizeof(list));
if(head == NULL)
{
printf("malloc error in init_list\n");
return NULL;
}
head->data = 0;
head->next = NULL;
return head;
}
int head_insert(plist head, int d)
{
plist p;
if(head == NULL)
{
printf("list error in insert\n");
return -1;
}
p = (plist)malloc(sizeof(list));
if(p == NULL)
{
printf("malloc error in insert\n");
return -1;
}
p->data = d;
p->next = head->next;
head->next = p;
return 0;
}
int tail_insert(plist head, int d)
{
plist p, q;
if(head == NULL)
{
printf("list error in insert\n");
return -1;
}
p = head;
while(p->next != NULL)
{
p = p->next;
}
q = (plist)malloc(sizeof(list));
if(q == NULL)
{
printf("malloc error in insert\n");
return -1;
}
q->data = d;
q->next = p->next;
p->next = q;
return 0;
}
void print_list(plist head)
{
plist p = head->next;
while(p)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
void free_list(plist head)
{
plist p, q;
p = head;
while(p)
{
q = p->next;
free(p);
p = q;
}
}
void free_ring_list(plist head, plist enc)
{
plist p, q;
p = head;
int flag = 0;
while(p)
{
if(p == enc)
{
if(flag == 0)
{
flag = 1;
}
else
{
return;
}
}
q = p->next;
free(p);
p = q;
}
}
#endif
update:
求环长
理论:
从快慢指针的相遇点开始,指针每次走一步,如果再次到达相遇点就是一圈,这样就记录了环长。
无代码无真相:
int get_ring_len(plist head)
{
int count = 0;
plist p, enc;
enc = encounter(head);
p = enc->next;
while(p != enc)
{
p = p->next;
count++;
}
count++;
return count;
}