【Java数据结构】判断单链表是否有环,并且找出环的入口

一:判断是否有环
       思路:使用快慢引用法解决 是否有环
                        假设链表是一个有环链表,且由f指向c构成环。那么  使用两个指针   A 和 B,让两指针同时向后遍历  而且B的遍历速度是A的两倍,呢么如果是有环的话,B终究会追上A。因此我们可以 以AB是否相遇作为判断是否有环的必要条件。

                     下面是图例:

 

 

最终BA在e相遇,于是可以得出   此链表有环。

代码:
 

public Entry<E> isLoop(){
        Entry<E> fast = first , slow = first;//定义两个指针,分别是快和慢
        //遍历一遍链表,如果最后是null的话就代表没有环
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            //如果俩相遇了,代表有环
            if (fast == slow){
                return fast;
            }
        }
        return null;
    }

二:求出成环的位置
思路:s=vt(路程=速度*时间)用方程思想列等式解
            因为路程知道,速度知道(二倍关系),时间也知道(相等),所以可以列等式求关系。再用代码体现出关系,就可以解决这道题了。

           如图:假设链表是Link   fast是快的那个指针,Slow是慢的呢个指针,蓝色是fast走过的路程,绿色是slow走过的路程

                K是环的入口,P是快慢指针相遇的地方

                 a,b,c 分别代表三段长度。

所以图就可以变成:

然后,让指针从   相遇点p   和起始点  同时遍历,这样由于   c = a  所以p和first在k相遇,而k就是入口点。   

 

代码:
 

public Entry<E> getIntersectEntry(){
        Entry<E> meet = isLoop();
        if(meet == null){
            return null;
        }
        Entry<E> p = meet;
        Entry<E> q = first;
        while (p!=q){
            p = p.next;
            q = q.next;
        }
        return p;
    }

无头结点单链表结构:

/*
* 不带头节点  的单链表
* */
public class NhLinkedList<E> {
    private class Entry<T> {
        private T value;
        private Entry<T> next;
 
        public Entry(){
 
        }
        public Entry(T value,Entry<T> next){
            this.value = value;
            this.next = next;
        }
    }
 
    private Entry<E> first;
    private Entry<E> last;
    private int size;
    public NhLinkedList(){
        first = null;
        last = null;
    }
 
 
    //             增
    //头插
    public void addHead(E value){
        first = new Entry<>(value,first);
        size++;
        if(last == null){
            last = first;
        }
    }
    //尾插
    public void addEnd(E value){
        Entry<E> entry = new Entry<>(value,null);
        size++;
        last.next = entry;
        last = entry;
        if(first == null){
            first = last;
        }
    }
    //第i个地方插入
    public void addIni(int i,E value){
        try {
            Entry<E> entryI = first;
            for (int p = 1; p < i - 1; p++) {
                entryI = entryI.next;
            }
            Entry<E> p = new Entry<>(value, entryI.next);
            size++;
            entryI.next = p;
        }catch (NullPointerException e){
            System.out.println(e);
        }
    }
 
 
    //             删
    //初始化单链表
    public void init(){
        first = null;
        last = null;
    }
    //删除第i个    ,,判断第i个是否可删除
    public void delI(int i){
        if(i>size || i<1){
            System.out.println("越界");
            return;
        }
        //头删
        if(i == 1){
            first = first.next;
            size--;
        }
        //尾删
        else if(i == size){
            last = null;
            size--;
        }
        //中间删除
        else {
            Entry<E> entryI = first;
            for (int p = 1; p < i-1; p++) {
                entryI = entryI.next;
            }
            entryI.next = entryI.next.next;
            entryI.next.value = null;
            entryI.next.next = null;
            size--;
        }
    }
 
 
    //             改
    //改第i个
    public void change(E value,int i){
        Entry<E> entryI = first;
        for(int p = 1;p < i;p++){
            entryI = entryI.next;
        }
        entryI.value = value;
    }
 
 
    //             查
    //查第i个
    public void searchI(int i){
        try {
            Entry<E> entryI = first;
            for (int p = 1; p < i; p++) {
                entryI = entryI.next;
            }
            System.out.println("第 "+i+" 个是: "+entryI.value);
        }catch (NullPointerException e){
            System.out.println("超出查询范围");
        }
    }
    //按查value
    public void searchV(E value){
        try {
            Entry<E> entryV = first;
            int i = 1;
            while (i < size) {
                if (entryV.value == value) {
                    System.out.println(value+"  在第 :" + i + "个");
                }
                entryV = entryV.next;
            }
            System.out.println("没有查到");
        }catch (NullPointerException e){
            System.out.println("超出查询范围");
        }
    }
    //查链表长度
    public int size(){
        int num = 0;
        for(Entry<E> p = first ; p!=null ; p=p.next){
            num++;
        }
        return num;
    }
 
   
    // 判断链表成环,并且求出环的位置
    public Entry<E> isLoop(){
        Entry<E> fast = first , slow = first;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow){
                return fast;
            }
        }
        return null;
    }
    public Entry<E> getIntersectEntry(){
        Entry<E> meet = isLoop();
        if(meet == null){
            return null;
        }
        Entry<E> p = meet;
        Entry<E> q = first;
        while (p!=q){
            p = p.next;
            q = q.next;
        }
        return p;
    }
 
    
    //打印链表
    public void show(){
        for(Entry<E> p = first ; p!=null ; p=p.next){
            System.out.print(p.value);
        }
    }
}


 
————————————————
版权声明:本文为CSDN博主「阎八一」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40879743/article/details/90646399

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值