单链表是否有环并如何找到环入口


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

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


一般通用的做法就是弄两个指针,一个走得快一点,一个走得慢一点。一般是弄一个走一步,一个走两步。这样如果他们相遇,则说明有环。

那么在有环的基础上,怎么找到这个环的入口?

所有的都用移动了多少步来说明。

走一步的指针叫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

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

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

public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead==NULL||pHead->next==NULL) return NULL;
        
        ListNode* p1=pHead;
        ListNode* p2=pHead;
        
        //寻找相遇点
        while(p1&&p1->next){
            p1=p1->next->next;
            p2=p2->next;
            if(p1==p2)
                break;
        }
        
        //寻找环的入口点
        p2=pHead;
        while(p1!=p2){
            p1=p1->next;
            p2=p2->next;
        }
        return p2;
    }



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

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

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


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值