# 有环单链表的结点个数的统计方法

int get_length(list_t *head)
{
int len = 0;
for (list_t *p = head; p != NULL; p = p->next)
len++;
return len;
}

• 首先，统计在环上的总的结点个数，不妨记为N1;
• 其次，找到环的入口结点，不妨记为Joint;
• 然后，从单链表的头结点开始到Joint结束，统计这一线性链表上的总的结点个数（不包括Joint），不妨记为N2;
• 最后，N1+N2就是有环单链表的总的结点个数。

 1 int get_total_length(list_t *head)
2 {
4
5         list_t *joint = (len != 0) ? get_loop_joint(head) : NULL;
6
7         for (list_t *p = head; p != joint; p = p->next)
8                 len++;
9
10         return len;
11 }

• L3的get_loop_length()是获取环上的总的结点个数。
• L5的get_loop_joint()是获取环的入口结点。

1. 判断一个单链表有环

 1 /**
2  * Detect a singly linked list has a loop
3  */
5 {
8
9         /*
10          * If loop does not exist, fast should firstly reach the end
11          * a) if the length of list is even, fast       will be NULL
12          * b) if the length of list is odd,  fast->next will be NULL
13          */
14         while (fast != NULL && fast->next != NULL) {
15                 fast = fast->next->next;
16                 slow = slow->next;
17
18                 /*
19                  * Well, loop is found as the fast catches up with the slow
20                  */
21                 if (fast == slow)
22                         return true;
23         }
24
25         return false;
26 }

2. 统计有环单链表的环上结点个数

 1 /**
2  * Get the length of the loop if a singly linked list has a loop
3  */
5 {
8         list_t *node = NULL;
9
10         /* get a node in the loop */
11         while (fast != NULL && fast->next != NULL) {
12                 fast = fast->next->next;
13                 slow = slow->next;
14
15                 if (fast == slow) {
16                         node = slow;
17                         break;
18                 }
19         }
20
21         /* no loop found hence the length should be zero */
22         if (node == NULL)
23                 return 0;
24
25         /* now walk again to get the length of the loop */
26         int len = 1;
27         for (list_t *p = node->next; p != node; p = p->next)
28                 len++;
29         return len;
30 }

3. 获取有环单链表的入口结点

• Joint到Node的长度记为Y1
• Node到Joint的长度记为Y2

C代码如下: (注释中也给出了严格的数学证明)

 1 /**
2  * Get the joint if a singly linked list has a loop
3  */
4 list_t *
6 {
9         list_t *node = NULL;
10
11         /* get a node in the loop */
12         while (fast != NULL && fast->next != NULL) {
13                 fast = fast->next->next;
14                 slow = slow->next;
15
16                 if (fast == slow) {
17                         node = slow;
18                         break;
19                 }
20         }
21
22         /* no loop found hence the joint should be NULL */
23         if (node == NULL)
24                 return NULL;
25
26         /*
27          * The slow walks the loop from the node, and let the fast walk the
28          * list from its head. They should meet at the joint.
29          *
31          *     |           |
32          *     O-->O-->O-->O<--O<--O
33          *                 |       ^
34          *                 V       |
35          *                 O-->O-->O
36          *                          \
37          *                           Node
38          *
39          *     x : The length from Head  to Joint
40          *     y1: The length from Joint to Node
41          *     y2: The length from Node  to Joint
42          *
43          *     Total steps of the slow walked: x + y1
44          *     Total steps of the fast walked: x + y1 + y2 + y1
45          *     Note the fast and the slow have the same times to move,
46          *     So                              x + y1 == (x + y1 + y2 + y1) / 2
47          *                                 ==> 2x + 2y1 == x + 2y1 + y2
48          *                                 ==> x == y2
49          */
51         slow = node;
52         while (fast != slow) {
53                 fast = fast->next;
54                 slow = slow->next;
55         }
56
57         return slow;
58 }

posted @ 2017-11-21 17:11  veli  阅读(455)  评论(0编辑  收藏