转载:http://www.cppblog.com/humanchao/archive/2008/04/17/47357.html
作者:胡满超 from:C++博客
有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。
问题:
1、如何判断一个链表是不是这类链表?
2、如果链表为存在环,如果找到环的入口点?
一、判断链表是否存在环,办法为:
设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,fast先行头到尾部为NULL,则为无环链表)程序如下:
Cpp代码
1.bool IsExitsLoop(slist *head)
2.{
3. slist *slow = head, *fast = head;
4.
5. while ( fast && fast->next )
6. {
7. slow = slow->next;
8. fast = fast->next->next;
9. if ( slow == fast ) break;
10. }
11.
12. return !(fast == NULL || fast->next == NULL);
13.}
bool IsExitsLoop(slist *head)
{
slist *slow = head, *fast = head;
while ( fast && fast->next )
{
slow = slow->next;
fast = fast->next->next;
if ( slow == fast ) break;
}
return !(fast == NULL || fast->next == NULL);
}
二、找到环的入口点
当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则 fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
2s = s + nr
s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:
Java代码
1.slist* FindLoopPort(slist *head)
2.{
3. slist *slow = head, *fast = head;
4.
5. while ( fast && fast->next )
6. {
7. slow = slow->next;
8. fast = fast->next->next;
9. if ( slow == fast ) break;
10. }
11.
12. if (fast == NULL || fast->next == NULL)
13. return NULL;
14.
15. slow = head;
16. while (slow != fast)
17. {
18. slow = slow->next;
19. fast = fast->next;
20. }
21.
22. return slow;
23.}
slist* FindLoopPort(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 NULL;
slow = head;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
扩展问题:
判断两个单链表是否相交,如果相交,给出相交的第一个点(两个链表都不存在环)。
比较好的方法有两个:
一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。
二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。
这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。
分享到:
相关推荐
在IT领域,尤其是在数据结构与算法的学习和面试中,判断单链表中是否存在环是一个非常典型且重要的问题。这个问题不仅考验了对链表这一数据结构的理解,还涉及到算法设计、循环检测等关键概念。 ### 题目背景 在...
这里我们深入探讨一下"面试单链表问题总结-反转,逆序输出,判环,求交点"这四个核心知识点。 首先,**单链表反转**是一个常见的面试题。单链表的基本结构由节点组成,每个节点包含数据和指向下一个节点的指针。...
在面试中,对单链表的基本操作是衡量开发者对数据结构理解和编程能力的重要指标。以下是关于单链表建立、查找、插入、删除及特殊操作——检查环、找中间元素和反转的详细知识点。 1. **建立单链表**: 建立单链表...
在实际编程竞赛或面试中,理解和熟练掌握单链表操作是至关重要的,因为它们是许多复杂算法的基础,如二分查找、哈希表、图算法等。对于C++程序员来说,能够高效地处理链表问题可以展示出扎实的数据结构基础和解决...
在众多的数据结构中,单链表是一个基础且重要的元素。本篇将详细探讨单链表相关的13道面试题,涵盖其基本操作、查找、反转等重要知识点。 1. **单链表反转**:单链表反转是一项常见的算法题目,主要考察对链表节点...
此外,文件中还提到了用链表模拟大整数加法运算,这是一个经典问题,它能够很好地测试应聘者对于复杂数据结构的理解和操作能力,尤其是在处理超出常规数据类型范围的问题时。 链表的排序也是面试中的常见题目。虽然...
这里我们聚焦于“数据结构面试常用经典问题”,通过分析《数据结构与算法经典问题解析:Java语言描述(原书第2版)》这本书中的内容,我们可以深入探讨几个关键知识点。 1. **数组**:数组是最基础的数据结构,它...
本文档涵盖了单链表目录的各种问题和解决方案,包括单链表反转、找出单链表的倒数第4个元素、找出单链表的中间元素、删除无头单链表的一个节点、两个不交叉的有序链表的合并、有个二级单链表的转换、一级单链表的...
这些链表操作是面试中常见的问题,对于程序员来说,理解和掌握这些基本操作是至关重要的,因为它们不仅涉及到基础的编程技巧,还涉及到算法设计和问题解决能力。熟练运用这些链表操作,可以为面试加分,提高在IT行业...
8. **判断单链表是否有环、找到环的起点和环的长度** - 使用快慢指针,快指针每次走两步,慢指针每次走一步。如果存在环,快指针会追上慢指针;找到相遇点,然后从相遇点开始,快慢指针都走一步,当再次相遇时的步...
【算法大全-面试题-数据结构1】这篇文章主要探讨了单链表的相关操作,这些操作在面试中常常作为考察点,对于理解数据结构和算法至关重要。以下是对文章中提到的知识点的详细说明: 1. **单链表反转**:单链表反转是...
总之,单链表是编程基础中的基础,无论是面试还是实际项目开发,都可能涉及到它的运用。熟练掌握单链表及其操作,能为你的IT职业生涯打下坚实的基础。通过不断地练习和实践,你将能够更好地应对各种复杂的问题。