链表带环问题求解?是否带环,环的入口点,环长度
2016-07-28 16:01
330 查看
(1)链表是否有环?
设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇,设碰撞点为p。(当然,fast如果为NULL,则为无环链表)程序如下:bool IsExitsLoop(slist *head) { slist *slow = head, *fast = head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } if (fast == NULL || fast->next == NULL) return false; return true; }
(2)找到环的入口点?
定理:slow和fast相遇点为p,让slow从head开始,fast从p开始,每次往后各走一步,直到slow和fast再次相遇,则相遇点即为环的入口。当快慢指针第一次相遇的时候,从相遇那个节点到环入口的节点和链表头结点到环入口的节点的距离相等,所以此时让一个指针从链头开始跑,一个指针从相遇的节点开始跑,那么相遇时,这个相遇节点便是环的入口节点。
那么会有一个问题:
这俩个距离为什么会相等,我们来证明一下。
当慢指针和快指针相遇的时候,快指针必然在环中转了n圈
所以有:2s = s + nr ; s为慢指针走过的距离,r 为环的长度
可以得出 s = nr
假设环入口到相遇节点的距离为x,链头节点到环入口的距离为a,链表长度为L
所以有 x + a = s ;由上面替换得到 x + a = nr ==> x+ a =(n-1)r +r ==> x + a = (n-1)r +L - a
所以有 a = (n-1)r +L - a - x;我们发现抛去转的圈数,刚好就是相遇节点到环入口的距离 == 链头节点到环入口的距离。
(L–a–x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
ListNode *FindLoopPort(slist *head) { ListNode *slow = head, *fast = head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } if (fast == NULL || fast->next == NULL) return NULL; slow = head; while (slow != fast) { slow = slow->next; fast = fast->next; } return slow; }
(3)如何知道环的长度?
记录下碰撞点meet,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度r。unsigned int GetLoopLength(slist *head) { ListNode*slow = head, *fast = head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } if (fast == NULL || fast->next == NULL) return 0; ListNode *meet = slow; slow = meet->next; fast = meet->next->next; unsigned int len = 1; while (slow != fast) { len ++; slow = slow->next; fast = fast->next->next; } return len; }
(4)带环链表的长度是多少?
L=a+r。(5)判断两个单链表是否相交?
判断两个单链表是否相交,如果相交,给出相交的第一个点(两个链表都不存在环)。比较好的方法有两个:
一、将其中一个链表L2首尾相连,检测另外一个链表L1是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。
二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。
相关文章推荐
- [C/C++]反转链表
- 网卡安装常见问题精解
- C#实现基于链表的内存记事本实例
- C#模拟链表数据结构的实例解析
- css网页布局中注意的几个问题小结
- 使用mysql中遇到的几个问题
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++利用静态成员或类模板构建链表的方法讲解
- C++实现简单的学生管理系统
- 装完linux以后需要注意的问题
- .net中前台javascript与后台c#函数相互调用问题
- JavaScript中0和""比较引发的问题
- Linux内核链表实现过程
- C++链表倒序实现方法
- C#通过链表实现队列的方法
- SQLite字符串比较时的大小写问题解决方法
- PHP动态规划解决0-1背包问题实例分析
- jquery1.8版本使用ajax实现微信调用出现的问题分析及解决办法
- Node.js环境下JavaScript实现单链表与双链表结构
- 搭建SSH时的思考和遇到的几个问题的解决方法