zoukankan      html  css  js  c++  java
  • 单链表是否有环并如何找到环入口

     1、如何判断一个链表是不是有环?   

    2、如果链表为存在环,如果找到环的入口点?


    这个算是一个比较老的题目了,之前就看到过,一般通用的做法就是弄两个指针,一个走得快一点,一个走得慢一点。一般是弄一个走一步,一个走两步。这样如果他们相遇,则说明有环。

    那么在有环的基础上,怎么找到这个环的入口呢,一般网上也会给出解释,可能是我的理解力比较底,网上的解释中,总是用移动

    了s步,又是长度的,总是弄的我很晕,于是,给出我自己的解释好了,所有的都用移动了多少步来说明。

    走一步的指针叫slow,走两步的叫fast。

    相遇的时候,slow共移动了s步,fast共移动了2s步,这个是显而易见的。

    定义a如下: 链表头移动a步到达入口点。

    定义x如下: 入口点移动x步到达相遇点。

    定义r如下: 从环中的某一点移动r步,又到达的这一点,也就是转了一圈的意思。

    定义t如下: 从相遇点移动到入口点的移动步数

    定义L如下: 从链表头移动L步,又到达了相遇点。也就是遍历完链表之后,通过最后一个节点的指针,又移动到了链表中的某一点。

    其中L = a + r  =  a + x + t

    那么slow和fast相遇了,fast必然比slow多走了n个圈,也就是 n*r 步,那么

    s = a + x   

    2s = s + n*r , 可得  s = n*r

    将s=a+x,带入s =n*r,可得 a+x = n*r, 也就是 a+x = (n-1)*r + r   

    从表头移动到入口点,再从入口点移动到入口点,也就是移动了整个链表的距离,即是 L =  a + r , 所以r = L - a

    所以   a+x = (n-1)*r + L - a ,   于是 a  = (n-1)*r + L - a - x = (n-1)*r + t

    也就是说,从表头到入口点的距离,等于从相遇点继续遍历又到表头的距离。

    所以,从表头设立一个指针,从相遇点设立一个指针,两个同时移动,必然能够在入口点相遇,这样,就求出了相遇点。

    代码如下:

    typedef struct node{
        int elem;
        struct node * next;
    }Node, *NodeList;
    
    //寻找环的入口点
    NodeList FindLoopPort(NodeList head)
    {
        NodeList 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指向开头,fast在相遇点
        //得到入口点
        slow=head;
        while(slow!=fast){
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }

    于是我又思考了一下,对于一个带环的链表如何遍历输出所有节点的值,因为不能够通过最后移动到NULL来判断结束。

    如果链表设置了尾节点(环入口点)的话,就通过比较是不是又到达了尾节点就可以作为结束条件了

    如果没有设置尾节点的话,那么在遍历的时候,把每个节点的地址放入一个set集合中,如果下一个地址在set中出现了,那么也就结束了。

    不知道有木有其他的方法了。

  • 相关阅读:
    子线程导致 Windows 服务停止的情况(Topshelf 结合 Quartz.NET)
    ASP.NET Web API 2 使用 DelegatingHandler(委托处理程序)实现签名认证
    ASP.NET Web API 2 使用 AuthorizationFilter(授权过滤器)实现 Basic 认证
    聚合函数查询语句
    SQL SERVER数据库常用命令
    Easyui-datebox日期控件增加清空按钮
    用sql语句查出来字段里包含某个字符串的所有记录
    String 转化成java.sql.Date和java.sql.Time(转载)
    常见的 HTML 事件
    JavaScript 变量中给数值加引号的问题
  • 原文地址:https://www.cnblogs.com/cyttina/p/2743760.html
Copyright © 2011-2022 走看看