判断两个链表是否相交

如果两链表都无环,直接判断尾是否相交,如果都有环,则判断一链表上指针相遇的节点(环入口点)在不在另一个链表上。方法如下:
【摘要】有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。1、如何判断一个链表是不是这类链表?2、如果链表为存在环,如果找到环的入口点?扩展:判断两个单链表是否相交,如果相交,给出相交的第一个点。

有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。

问题:

1、如何判断一个链表是不是这类链表?
2、如果链表为存在环,如果找到环的入口点?

解答:

一、判断链表是否存在环,办法为:

设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,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
;
    }

    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)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。

程序描述如下:

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;
}

 

附一种易于理解的解释:

 

一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):
关于这个解法最形象的比喻就是在操场当中跑步,速度快的会把速度慢的扣圈

可以证明,p2追赶上p1的时候,p1一定还没有走完一遍环路,p2也不会跨越p1多圈才追上

我们可以从p2和p1的位置差距来证明,p2一定会赶上p1但是不会跳过p1的

因为p2每次走2步,而p1走一步,所以他们之间的差距是一步一步的缩小,4,3,2,1,0 到0的时候就重合了

根据这个方式,可以证明,p2每次走三步以上,并不总能加快检测的速度,反而有可能判别不出有环

既然能够判断出是否是有环路,那改如何找到这个环路的入口呢?

解法如下: 当p2按照每次2步,p1每次一步的方式走,发现p2和p1重合,确定了单向链表有环路了

接下来,让p2回到链表的头部,重新走,每次步长不是走2了,而是走1,那么当p1和p2再次相遇的时候,就是环路的入口了。

这点可以证明的:

在p2和p1第一次相遇的时候,假定p1走了n步骤,环路的入口是在p步的时候经过的,那么有

p1走的路径: p+c = n;         c为p1和p2相交点,距离环路入口的距离

p2走的路径: p+c+k*L = 2*n;   L为环路的周长,k是整数

显然,如果从p+c点开始,p1再走n步骤的话,还可以回到p+c这个点

同时p2从头开始走的话,经过n步,也会达到p+c这点

显然在这个步骤当中p1和p2只有前p步骤走的路径不同,所以当p1和p2再次重合的时候,必然是在链表的环路入口点上。

 

 

 

扩展问题:

判断两个单链表是否相交,如果相交,给出相交的第一个点(两个链表都不存在环)。

比较好的方法有两个:

一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。

二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。

这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。

转自:http://keep.iteye.com/blog/293454

http://blog.csdn.net/linyunzju/article/details/7753548

在判定有无环时候我们能够分别找出两个链表的相遇点pos1, pos2,然后还是使用两个指针fast和slow,都初始化为pos1,且fast每次前进2步,slow每次前进1步。若fast指针在遇到slow前,出现fast等于pos2或fast->next等于pos2,则说明两个链表相交,否则不相交。若两链表相交,我们可知pos2肯定是两个链表的一个相交点,将这个点看做两个链表的终止节点,使用(3)中的解法,即可找到两个链表相交的第一个节点。

[cpp]
  1. #include <iostream>  
  2. #include <algorithm>  
  3. using namespace std;  
  4.   
  5. struct Link  
  6. {  
  7.     int data;  
  8.     Link *next;  
  9. };  
  10.   
  11. // 插入节点  
  12. void insertNode(Link *&head, int data)  
  13. {  
  14.     Link *node = new Link;  
  15.     node->data = data;  
  16.     node->next = head;  
  17.     head = node;  
  18. }  
  19.   
  20. // 判断链表是否存在环  
  21. Link* hasCycle(Link* head)  
  22. {  
  23.     Link *fast, *slow;  
  24.     slow = fast = head;  
  25.     while (fast && fast->next)  
  26.     {  
  27.         fast = fast->next->next;  
  28.         slow = slow->next;  
  29.         if (fast == slow)  
  30.             return slow;  
  31.     }  
  32.     return NULL;  
  33. }  
  34.   
  35. // 确定环的入口点,pos表示fast与slow相遇的位置  
  36. Link* findCycleEntry(Link* head, Link* pos)  
  37. {  
  38.     while (head != pos)  
  39.     {  
  40.         head = head->next;  
  41.         pos = pos->next;  
  42.     }  
  43.     return head;  
  44. }  
  45.   
  46. // 找到两个链表相交的第一个交点(链表可能会有环)  
  47. Link* findFirstCross(Link* head1, Link* head2)  
  48. {  
  49.     Link* pos1 = hasCycle(head1);  
  50.     Link* pos2 = hasCycle(head2);  
  51.     // 一个链表有环,另一个链表没环,那肯定没有交点  
  52.     if (pos1 && !pos2 || !pos1 && pos2)  
  53.         return NULL;  
  54.     Link *nd1, *nd2;  
  55.     // 两个链表都没有环  
  56.     if (!pos1 && !pos2)  
  57.     {  
  58.         // 记下两个链表的长度  
  59.         int len1, len2;  
  60.         len1 = len2 = 0;  
  61.         nd1 = head1;  
  62.         while (nd1) {len1++;nd1=nd1->next;}  
  63.         nd2 = head2;  
  64.         while (nd2) {len2++;nd2=nd2->next;}  
  65.         // 较长链表的链表的nd先走dif步  
  66.         int dif;  
  67.         nd1 = head1; nd2 = head2;  
  68.         if (len1 >= len2)  
  69.         {  
  70.             dif = len1 - len2;  
  71.             while (dif--) nd1=nd1->next;  
  72.         }  
  73.         else  
  74.         {  
  75.             dif = len2 - len1;  
  76.             while (dif--) nd2=nd2->next;  
  77.         }  
  78.         // 之后两个nd再一起走,直到某个nd为NULL(不相交)  
  79.         // 或直到nd相等(即为第一个交点)  
  80.         while (nd1 && nd2)  
  81.         {  
  82.             if (nd1==nd2)  
  83.                 return nd1;  
  84.             nd1=nd1->next;  
  85.             nd2=nd2->next;  
  86.         }  
  87.         return NULL;  
  88.     }  
  89.     // 两个链表都有环  
  90.     if (pos1 && pos2)  
  91.     {  
  92.         // 判断这两个环是不是同一个环  
  93.         Link *tmp = pos1;  
  94.         do  
  95.         {  
  96.             if (pos1 == pos2 ||pos1->next == pos2)  
  97.                 break;  
  98.             pos1 = pos1->next->next;  
  99.             tmp = tmp->next;  
  100.         }while (pos1!=tmp);  
  101.         // 两个链表的环不是同一个环,所以没有交点  
  102.         if (pos1 != pos2 && pos1->next != pos2)  
  103.             return NULL;  
  104.         // 两个链表有共同的交点pos1,现在求第一个交点  
  105.         int len1, len2;  
  106.         len1 = len2 = 0;  
  107.         Link *nd1, *nd2;  
  108.         nd1 = head1;  
  109.         while (nd1 != pos1) {len1++;nd1=nd1->next;}  
  110.         nd2 = head2;  
  111.         while (nd2 != pos1) {len2++;nd2=nd2->next;}  
  112.         // 较长链表的链表的nd先走dif步  
  113.         int dif;  
  114.         nd1 = head1; nd2 = head2;  
  115.         if (len1 >= len2)  
  116.         {  
  117.             dif = len1 - len2;  
  118.             while (dif--) nd1 = nd1->next;  
  119.         }  
  120.         else  
  121.         {  
  122.             dif = len2 - len1;  
  123.             while (dif--) nd2 = nd2->next;  
  124.         }  
  125.         // 之后两个nd再一起走,直到nd相等(即为第一个交点)  
  126.         while (nd1!=pos1 && nd2!=pos1)  
  127.         {  
  128.             if (nd1 == nd2)  
  129.                 return nd1;  
  130.             nd1 = nd1->next;  
  131.             nd2 = nd2->next;  
  132.         }  
  133.         return pos1;  
  134.     }  
  135. }  
  136.   
  137. int total[] = {8, 2, 5};  
  138. int C[10] = {15, 14, 13, 12, 11, 10, 9, 8};  
  139. int B[10] = {7, 6};  
  140. int A[10] = {5, 4, 3, 2, 1};  
  141.   
  142. int main()  
  143. {  
  144.     Link *headB, *headA;  
  145.     headB = headA = NULL;  
  146.     int i;  
  147.     for (i=0; i<total[0]; i++)  
  148.         insertNode(headB, C[i]);  
  149.     Link *nd = headB;  
  150.     while (nd->next) nd = nd->next;  
  151.     // 8->9->10->11->12->13->14->15->10->11->12->...  
  152.     nd->next = headB->next->next;  
  153.     headA = headB;  
  154.     // B: 6->7->8->9->10->...->15->10->...  
  155.     for (i=0; i<total[1]; i++)  
  156.         insertNode(headB, B[i]);  
  157.     // A: 1->2->3->4->5->8->9->10->...->15->10->...  
  158.     for (i=0; i<total[2]; i++)  
  159.         insertNode(headA, A[i]);  
  160.     // find: 8  
  161.     Link *pos = findFirstCross(headA, headB);  
  162.     if (pos)  
  163.         printf("yes: %d\n", pos->data);  
  164.     else  
  165.         printf("no\n");  



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313418.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS Code 1.39 发布!Web 版 VS Code 是否离我们越来越近了?(文末彩蛋)

今天&#xff08;北京时间 2019 年 10 月 10 日&#xff09;&#xff0c;微软发布了 Visual Studio Code 1.39 版本。此版本主要更新的内容包括&#xff1a;Source Control tree view - 可以通过列表或者树状图两种方式来展示被改变的文件。Toggle region folding keyboard sho…

Java引用类型——强引用、软引用、弱引用和虚引用

Java执行GC判断对象是否存活有两种方式其中一种是引用计数。 引用计数&#xff1a;Java堆中每一个对象都有一个引用计数属性&#xff0c;引用每新增1次计数加1&#xff0c;引用每释放1次计数减1。 在JDK 1.2以前的版本中&#xff0c;若一个对象不被任何变量引用&#xff0c;那么…

二叉树分析(两点最大距离)

转载自&#xff1a;http://blog.csdn.net/lalor/article/details/7626678 http://blog.csdn.net/lalor/article/details/7618120 把二叉树看成一个图&#xff0c;父子节点之间的连线看成是双向的&#xff0c;我们姑且定义"距离"为两节点之间边的个数。写…

IT从业的迷思与破解之道(更新)

我只是单纯做技术的程序员&#xff0c;什么靠微信广告攒钱这些&#xff0c;跟我没有半毛钱关系&#xff0c;初衷很简单&#xff0c;只重视正三观的正确技术知识分享在这到处都是线上培训&#xff0c;付费知识的社群里&#xff0c;随便搜个词都有您想要的内容哪轮到我们。技术的…

graphcut 用于最优缝合先寻找_Image Stitching

Graphcut 求解最佳缝合线&#xff1a; 主要参照硕士学位论文《基于不同视点样图的图像修复》 Graphcut 主要参照&#xff1a; http://blog.csdn.net/zouxy09/article/details/8532111 Graph cuts是一种十分有用和流行的能量优化算法&#xff0c;在计算机视觉领域普遍应用于…

最后一个单词的长度

题目描述 给定一个仅包含大小写字母和空格 ’ ’ 的字符串&#xff0c;返回其最后一个单词的长度。 如果不存在最后一个单词&#xff0c;请返回 0 。 说明&#xff1a;一个单词是指由字母组成&#xff0c;但不包含任何空格的字符串。 示例: 输入: "Hello World"…

.netcore 开发的 iNeuOS 物联网平台部署在 Ubuntu 操作系统,无缝跨平台

1. 概述参见前两篇文章&#xff1a;《iNeuOS完全使用.netcore开发&#xff0c;主要为企业、集成商打造从网关、边缘应用、云端建设的物联网/工业互联网平台产品级解决方案。面向应用场景&#xff1a;&#xff08;1&#xff09;嵌入式硬件网关的开发和部署&#xff0c;形成自己…

按照前序遍历和中序遍历构建二叉树

转载自&#xff1a;http://blog.csdn.net/sbitswc/article/details/26433051 Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree. There is an example._______7______/ …

线程间通讯方式

线程间通讯方式 1&#xff1a;同步&#xff08;synchronized&#xff09; 2&#xff1a;共享变量&#xff08;volatile&#xff09; 2&#xff1a;wait/notify()机制 3&#xff1a;管道通信就是使用java.io.PipedInputStream 和 java.io.PipedOutputStream进行通信 进程间…

刷新:重新发现.NET与未来

是新朋友吗&#xff1f;记得先点蓝字关注我哦&#xff5e;微软在比尔盖茨手中创立并崛起, 成为PC互联网时代的霸主&#xff0c;很多70&#xff0c;80后都有MVP Edi Wang 的体验<“ 当时的微软对我来说就是神的存在。因为我认识电脑到使用电脑的一切几乎都离不开这家伟大的公…

OpenCV Stitching_detailed 详解

算法流程函数&#xff1a; 1. (*finder)(img, features[i]) Mathematical explanation: Refer to BRIEF: Binary Robust Independent Elementary Features and ORB: An efficient alternative to SIFT or SURF ...\sources\modules\stitching\src\matchers.cpp void OrbFe…

合并区间

题目描述 给出一个区间的集合&#xff0c;请合并所有重叠的区间。 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].示例 2: 输入: [[1,4],[4,5]] 输出: [[1,5]] 解释: 区间 [1,4] 和 [4,5]…

程序员修神之路--设计一套RPC框架并非易事

菜菜哥&#xff0c;我最近终于把Socket通信调通了这么底层的东西你现在都会了&#xff0c;恭喜你离涨薪又进一步呀http协议不也是利用的Socket吗可以这么说&#xff0c;http协议是基于TCP协议的&#xff0c;底层的数据传输可以说是利用的socket既然Socket通信会了&#xff0c;那…

GPU Shader 编程基础

转载自&#xff1a;http://www.cnblogs.com/youthlion/archive/2012/12/07/2807919.html 几个基本概念&#xff1a; Vertex buffer&#xff1a;存储顶点的数组。当构成模型的所有顶点都放进vertex buffer后&#xff0c;就可以把vertex buffer送进GPU&#xff0c;然后GPU就可…

Azure pipeline 配置根据条件执行脚本

Azure pipeline 配置根据条件执行脚本Intro我的应用通过 azure pipeline 来做持续集成&#xff0c;之前已经介绍了根据不同分支去打包不同的package&#xff0c;具体的就不再这里详细介绍了&#xff0c;可以参考 Solution来看一下修改之后的 azure-pipelines.yaml 示例配置吧&a…

监督学习和非监督学习

转自&#xff1a;http://blog.csdn.net/warrior_zhang/article/details/41453327 机器学习的常用方法&#xff0c;主要分为有监督学习(supervised learning)和无监督学习(unsupervised learning)。 监督学习&#xff0c;就是人们常说的分类&#xff0c;通过已有的训练样本&am…

C# 8 新特性 - 可空引用类型

Nullable Reference Type.在写C#代码的时候&#xff0c;你可能经常会遇到这个错误&#xff1a; 但如果想避免NullReferenceException的发生&#xff0c;确实需要做很多麻烦的工作。 可空引用类型 Null Reference Type 所以&#xff0c;C# 8的可空引用类型就出现了。 C# 8可以让…

Spring boot starter

1&#xff1a;Spring boot starter及项目中的类似运用 1&#xff1a;Spring boot starter的两种方式 引入pom文件&#xff0c;自动管理jar版本根据spring.factories配置文件&#xff0c;加载config的各种bean spring boot约定大于配置理念在这里有体现。 2&#xff1a;项目…

统计学习笔记(1) 监督学习概论(1)

原作品&#xff1a;The Elements of Statistical Learning Data Mining, Inference, and Prediction, Second Edition, by Trevor Hastie, Robert Tibshirani and Jerome Friedman An Introduction to Statistical Learning. by Gareth JamesDaniela WittenTrevor Hastie andR…

.NET Core 3.0之深入源码理解ObjectPool(一)

写在前面对象池是一种比较常用的提高系统性能的软件设计模式&#xff0c;它维护了一系列相关对象列表的容器对象&#xff0c;这些对象可以随时重复使用&#xff0c;对象池节省了频繁创建对象的开销。它使用取用/归还的操作模式&#xff0c;并重复执行这些操作。如下图所示&…