链表带环的问题研究及代码实现
2017-09-03 00:24
447 查看
链表带环的问题研究及代码实现
[TOC]完整源代码见:
https://github.com/lankuohsing/DataStructureInCPP/tree/master/DataStructureInCPP/Linked_List_with_Loop
注:如无特别说明,本文中的链表均含有附加表头结点first
1. 如何判断链表是否有环?
思路是让两个指针slow和fast同时从链表头出发遍历链表,fast的速度是slow的两倍(为简单起见我们可以让slow每次走一个节点,fast每次走两个节点),若slow和fast相遇,则说明有环。代码如下:
bool::Linked_List_with_Loop::isLoop ( ) { LinkNode*slow, *fast; slow = fast = first->link; if ( fast==NULL ) { return false; } while ( fast->link&&fast->link->link ) { slow = slow->link; fast = fast->link->link; if ( slow==fast ) { return true; } } }
2. 如何计算环的长度?
先给答案:第一次相遇(超一圈)时开始计数,第二次相遇时停止计数。具体推导如下:
如上图所示,设链表总长为L,链表头距离环的入口长度为a,环的入口点距离相遇点长度为x,环的长度为R
设slow的速度为v,fast的速度为2v。无论它们在环上哪一点相遇,它们再次相遇所需时间为R/(2v-v)=R/v。到下一次相遇时,slow走的距离刚好为R,也即得到环的长度。
代码如下:
int Linked_List_with_Loop::getLoopLength ( ) { LinkNode*slow, *fast; slow = fast = first->link; int loopLength = 0; if ( fast == NULL ) { return loopLength; } bool isMeet = false; while ( fast->link&&fast->link->link ) { slow = slow->link; fast = fast->link->link; if ( slow == fast ) { isMeet = true; } if ( isMeet ) { loopLength++; if ( slow->link == fast->link->link ) { break; } } } return loopLength; }
3. 如何得到环的入口点
先给答案:让两个指针分别从表头和相遇点开始走,速度一样,均为每次走一个节点,相遇时的那个点就是连接点。首先我们证明,当slow和fast相遇时,slow还没走完环的一圈,而fast已经走了超过一圈的路程。证明如下:
假设当slow刚到入口点时,fast已经走了nR+b(n≥0,,0≤b<R,n和b不同时为0)。当b=0时,说明slow和fast在入口点相遇,这时slow显然还没走完环的一圈,fast走完了大于1的整数圈;当0<b<R时,fast追上slow的时间为(R-b)/v,追及过程中slow走的距离为R-b,也即说明slow还没走完一圈,而fast走过的距离为2R-2b,加上之前走的nR+b,总共走完了环上的距离为(2+n)R-b>R。得证。
进一步我们可以得到相遇点距离入口点的长度为b
第一次相遇时,slow走了s=a+x步,fast走了2s=s+nR步,也即a+x=nR,也即a=(n-1)R+R-x,也即说明如果此时两个指针分别从表头和相遇点同时同速走,一定会在环的入口点相遇。
代码如下:
LinkNode * Linked_List_with_Loop::getLoopStartNode ( ) { LinkNode*slow, *fast; LinkNode * loopStartNode = NULL; slow = fast = first->link; if ( fast == NULL ) { return NULL; } bool isMeet = false; while ( fast->link&&fast->link->link ) { slow = slow->link; fast = fast->link->link; if ( slow == fast ) { isMeet = true; break; } } if ( isMeet ) { fast = first->link; while ( true ) { slow = slow->link; fast = fast->link; if ( slow == fast ) { loopStartNode = slow; break; } } } return loopStartNode; }
相关文章推荐
- 带环单链表及链表相交问题的分析及代码实现
- 两个超大正整数相加问题之链表实现(代码惨不忍睹,慎进)
- 判断两个链表是否相交,若相交,求交点,考虑带环情况实现代码
- (Java代码实现)单链表有环的一系列问题
- 约瑟夫问题的单向循环链表的代码实现
- 《C语言实现链表相交、带环问题》
- access如何用代码在“默认值”里实现自动编号?单据流水号生成问题。
- 研究了三天的文件上传(jspsmart实现)file和text表单同时提交的问题
- 单链表的倒置实现代码
- 使用链表实现Josephus环问题
- 用多线程实现“生产者-消费者问题”(代码+实验报告)
- 请大家看一下一个c语言中的链表问题,下面的代码是有错误的!!请大家说出错误的原因,以及修改的方法!!!
- 个人研究《数据结构与算法分析-C++描述》Vector实现的问题,new与初始化
- Linux 内核代码赏析与应用(二)-链表之实现
- 用winpcap实现局域网DNS欺骗之三(代码部分及深入研究)
- MinimizeName在C#中的实现代码(解决了我那个GDI+的问题)
- Singleton模式的C++实现研究(示例代码)
- 连续邮资问题的实现代码
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现,附代码)
- Singleton模式的C++实现研究(示例代码)