检测单链表是否有环新解

来源:互联网 发布:网络老虎机赌博网站 编辑:程序博客网 时间:2024/06/05 08:05

检测单链表是否有环有好几种方法。

  • 可以设置两个指针前后步遍历链表,但是这个不好确定环的T型交叉点。
  • 如果数据结构可以改就直接加个flag变量表示是否已经被遍历就可以,这个是最简单,但是一般要在不能改数据结构的情况下检测出环。
  • 我自己还能想到就是初步估计链表的长度,利用链表节点的地址构建一个散列表,访问一个节点就把这个节点的地址放到散列表里面,这个要额外的数据结构来支持算法,在链表节点比较少的情况下额外的内存消耗不会太大。
昨天真正把这个问题想了一下,琢磨小问题有时候还是挺有意思的,从上面的方法来看最简单最好用的当然就是第二个增加变量,这个可以很好的检测出环和节点。又好好想想此时的flag只是当作一个标志,只需要一个bool变量或者一位就可以,想到只要一位就很好办,难道就没有一位是永远空出来的吗。下面先看看单链表结构体的定义。

struct test{char c;struct test* next;};
其中的c只是测试用的,没什么含义。从结构体的定义可以看出点问题了。结构体分配内存的时候地址会对齐结构体里面成员字节数最大的那一个,也就是说,单链表节点的地址会四字节对齐,因此单链表节点地址的最后两位永远是0,也就是说next指针的最后两位肯定是0了, 这就给我们提供一个flag,只要遍历一个节点将next的最后一位设为1就ok啦。

下面看看程序吧

struct test* test_cycle(struct test* head){unsigned long addr = 0;struct test* prev;while(head->next){prev = head;addr = (unsigned long)head->next;if(addr & 0x01) //检测最后一位是否为1return head;head = head->next;prev->next = (struct test*)(addr | 0x01);  //最后一位设1}return 0;}int _tmain(int argc, _TCHAR* argv[]){struct test t1 = {'a', 0};struct test t2 = {'b', 0};struct test t3 = {'c', 0};struct test t4 = {'d', 0};struct test t5 = {'e', 0};t1.next = &t2;t2.next = &t3;t3.next = &t4;t4.next = &t5;t5.next = &t3;struct test* t_joint = test_cycle(&t1);if(t_joint)printf("%c", t_joint->c);return 0;}
这个程序最后没有将所有next指针还原了,只要遍历一下将所有的next的最后一位重置为0就行了。

原创粉丝点击