zoukankan      html  css  js  c++  java
  • c 链表之 快慢指针 查找循环节点(转)

     上面分析了 根据这张图

    推倒出 数学公式。 刚接触 不能一下弄明白。下面结合上面文章的分析。仔细推倒一下 ,

    一般设置 快指针 速度是 慢指针的2倍。及 快指针每次遍历两个指针, 慢指针每次遍历1个指针。

    假设上图 快慢指针 在E点相遇,那 相遇点离循环节点D 之间距离是X.  头结点A 离循环节点D 距离为K.

    那么在两指针相遇时,各自走过得距离(这里可以吧上图想成是 一个操场,起点不在操场内):

    慢指针:

    K + X + n*(X+Y) = m;//X+Y 绕环一圈的距离;n 慢指针 总共绕了几圈在环内.

    快指针:

    试想下 快指针是慢指针 速度的2倍,当它们相遇时 所用的时间是一样的。那么快指针 走过得距离是

    2*m;

    也等于

    K+X +N*(X+Y) = 2*m;//N为快指针绕过得圈数

    联立做差上面两公式。

    (N-n)*(X+Y) = m; 及

     (N-n)*(X+Y) = K+X+n*(X+Y);//这里X+Y 环长是个定值。 假设环长为M

    有:(N-n)*M = K+X+n*M;

    有:K+X = (N-2*n)*M ;

    最终的推倒公式 出来啦。及头节点A 到 循环节点D 的距离  加上  相遇点E离循环节点D  是 环长的整数倍。

    这个公式试用于 0 型循环链表  和 6型循环链表。

    对于前者 起K 和 X 都为0;快慢指针起点都是循环节点(0型 任意一点都是循环节点)
    那么有 (N-2*n)*M = 0;

    及 N = 2*n;  相遇时 快慢指针所绕 环的圈数 前者是后者的2倍。 可以想象速度是2呗,所用时间相同。

    这里跟环有多少节点没有关系。

    上面只是找到了相遇节点。如何找到循环节点。对于6型循环链表。

    还是上面推倒公式:

    K+X = (N-2*n)*M;//假设N-2*n = Q; 单位为圈数。

    有K+X=Q*M;   //再假设快慢指针能再循环节点相遇,那么X = 0;

    K = Q*M; //Q 的值和K 成正比,这个公式成立条件是 快慢指针相遇 在环上的任意一个点,

    假如是E点,结合公式  从E点转Q*M个节点 正好= K 。K的终点正好是循环节点D,及 如果快指针从起点A 走过K  和 慢节点 从E 走过M*Q 相遇节点正好是D循环节点,前提是快慢指针速度相同。

    假设将快指针 从头节点开始。慢指针从上次快慢指针相遇点 开始。 两者已相同速度移动。

    当快指针走的D 循环节点走过距离为K,慢指针 走到D 循环节点走过的距离为Q*M;

    此时 二者相遇 节点就是循环节点。

    分析下代码:

     1 Node* findBeginning(Node *pHead)  
     2 {  
     3     if (NULL == pHead)  
     4         return NULL;  
     5   
     6     Node *fast = pHead;  
     7     Node *slow = pHead;  
     8   
     9     /*判断是否存在环*/  
    10     while (fast->pnext != NULL)  //两种情况会跳出循环    
    11     {  
    12         fast = fast->pnext->pnext;  
    13         slow = slow->pnext;  
    14   
    15         if (NULL == fast)  
    16             return NULL;  
    17         if (fast == slow)  
    18             break;  
    19     }  
    20   
    21     if (NULL == fast->pnext)  //判断是哪种情况导致跳出循环    
    22         return NULL;  
    23   
    24     /*查找环起点*/  
    25     fast = pHead;  
    26     while (fast != slow)  
    27     {  
    28         fast = fast->pnext;  
    29         slow = slow->pnext;  
    30     }  
    31   
    32     return fast;  
    33 }  

    关于快慢指针算法:

      不仅限于 循环链表问题。

    比如查找一个  未知长度链表中中心节点

    可以先遍历长度,在遍历到长度/2处返回节点。显然这样 算法不够优化,

    使用快慢指针 遍历。快指针速度为 慢得 2倍。

    快指针遍历完,返回的慢指针 正好是 长度/2 的节点。

    转自:http://www.cnblogs.com/tangbinblog/p/4125842.html

  • 相关阅读:
    Oracle11gR2导入导出实战之物化视图prebuilt
    Oracle11gr2_ADG管理之switchover补充
    Oracle11gR2--手工建库&dbca建库
    Oracle11gr2_ADG管理之在备库上模拟failover的过程实战
    自己写个验证码类
    隐藏字符 BOM
    jquery与自己写的js文件冲突解决办法
    javaBean
    序列化
    UML
  • 原文地址:https://www.cnblogs.com/zl1991/p/6958202.html
Copyright © 2011-2022 走看看