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

 

 

 

 

 

©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页