- 论坛徽章:
- 0
|
各位给了很多方法,可惜没给代码,小弟也就没认真看了。
长期做系统程序,算法思维僵化了,想从现在开始锻炼锻炼,我就直接贴代码了。
算法很笨,先用不同步长前进找到圈,然后把圈中所有元素存到数组中(c99动态数组),最后再从链表头走一遍,第一个在数组中存在的元素就是圈的首节点。
不会算复杂度,估计是O(n^3)左右了, 太烂了,开始练习算法。
- #include <stdio.h>
- #include <stdlib.h>
-
- typedef struct list
- {
- int val;
- struct list *next;
- } list_t;
复制代码
- //不用细看,用来产生带圈的链表。
- //len参数指定链表长度,loop_pos指定最后一个元素指向链表中的第几个元素。
- //loop_pos如果大于len,则链表尾指向链表头。
- list_t *pro_list(int len, int loop_pos)
- {
- list_t *head = malloc(sizeof(list_t));
- list_t *t = head, *n = head;
- int i;
- head->val = 0;
-
- for ( i=1; i<len; i++ )
- {
- list_t *m = malloc(sizeof(list_t));
- m->val = i;
- t->next = m;
- t = m;
- }
-
- if ( loop_pos <= len )
- for ( i=0; i<loop_pos; i++ )
- n = n->next;
-
- t->next = n;
-
- return head;
- }
-
复制代码
- //链表打印函数,不用细看
- void print_list(list_t *head)
- {
- list_t *t = head;
- while (1)
- {
- printf("val:%d, addr:%p\n", t->val, t);
- if ( NULL == t->next )
- break;
-
- t = t->next;
- }
- }
复制代码
- //用来找圈的头节点,被find_loop调用
- //addr保存的是圈中所有节点的地址,head指向链表头,lo_len表示圈中有多少个节点
- list_t *find_loop_begin(list_t *addr[], list_t *head, int lo_len)
- {
- int i;
- list_t *t = head;
-
- while (1)
- {
- for ( i=0; i<lo_len; i++ )
- if ( addr[i] == t )
- return addr[i];
-
- t = t->next;
- }
-
- // should not be here
- return NULL;
- }
- list_t *find_loop(list_t *head)
- {
- list_t *t1 = head;
- list_t *t2 = head->next;
-
- while (1)
- {
- if ( t1 == t2 )
- {
- int lo_len = 1;
- int i = 1;
- t1 = t1->next;
- //先找出圈中有多少个节点
- while ( t1 != t2 )
- {
- lo_len ++;
- t1 = t1->next;
- }
- //把圈中的所有几点存入数组
- list_t *addr[lo_len];
- addr[0] = t2;
- t1 = t2->next;
- while ( t1 != t2 )
- {
- addr[i++] = t1;
- t1 = t1->next;
- }
- //找出圈中的第一个节点
- return find_loop_begin(addr, head, lo_len);
- }
- t1 = t1->next;
- t2 = t2->next->next;
- }
-
- return t1;
- }
复制代码
- int main()
- {
- list_t *head = pro_list(20, 11);
- list_t *lo = find_loop(head);
- printf("val:%d, addr:%p\n", lo->val, lo);
- //print_list(head);
-
- }
复制代码 |
|