什么是环?
  

  单链表有环,是指单链表中某个节点的next指针域指向的是链表中在它之前的某一个节点,这样在链表的尾部形成一个环形结构。

Java 链表中环的检测 链表有环怎么判断java_Java


  如上图,最后一个节点指向了第三个节点,所以后面四个节点构成了一个环,怎么判断单链表是否有环呢?

一.快慢指针法判断有无环:

  1.算法思路:可以定义快慢指针(fast和slow),让fast每次步径是slow的两倍,因为fast是两步两步走,所以注意循环条件(fast!=null && fast.next!=null),如果单链表有环,fast速度是slow的两倍,所以肯定会有一个时刻两个指针相遇,相遇即代表链表有环。
 (就和在操场上跑步的两个人一样,操场就代表着一个环,一个速度是另一个的两倍,速度快的肯定会有一个时刻追上速度慢的且处在同一个位置) 
  2.参考代码:

import java.util.List;

class ListNode{
    public int data;
    public ListNode next;


    public ListNode(int data){
        this.data=data;
        this.next=null;
    }
}//节点类

class MySignalList {
    public ListNode head;


    public MySignalList() {
        this.head = null;
    }

    //尾插法
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        if (this.head == null) {
            this.head = node;
        } else {
            ListNode cur = head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = node;
        }

    }


    //人为创造一个环
    public void cycle(){
        ListNode cur=this.head;
        while(cur.next!=null){
            cur=cur.next;
        }
        cur.next=this.head.next;
    }

    //有无环
    public boolean hasCycle(){
        ListNode fast=this.head;
        ListNode slow=this.head;
        while(fast!=null && fast.next!=null){
            slow=slow.next;         //slow每次走一步
            fast=fast.next.next;    //fast每次走两步
            if(slow==fast){         //判断两指针是否相遇
                return true;
            }
        }
        return false;
    }
}

public class Test {
        public static void main(String[] args) {
            MySignalList my = new MySignalList();
            my.addLast(1);
            my.addLast(5);
            my.addLast(76);
            my.addLast(12);
            my.addLast(16);
            my.cycle();
            boolean i=my.hasCycle();
            if(i==true){
                System.out.println("有环");
            }else{
                System.out.println("没有环");
            }

        }
}



//打印结果
有环

   

二.判断环入口点

  1.算法思路:
       ①先找到快慢指针第一次相遇的位置
       ②把其中一个指针拉到链表头
       ③之后再让快慢指针一人一步走,再次相遇的点就是环的入口处

  2.原理如图:

Java 链表中环的检测 链表有环怎么判断java_Java_02


  假设链表总长为n,表头到环入口点距离为x,环入口点到第一次相遇的位置为y。因为fast速度是slow的两倍,所以fast走过的距离是slow的两倍

  即2(x+y)=n+y ----- n=2x+y,所以可得第一次相遇点到链表尾部距离也为x,将slow移到head位置,此时可以看到slow距离环的入口点距离为x,fast距离环的入口点距离也为x,两个距离环入口点距离相等,之后一人一步走,肯定会在环的入口点相遇。 

  3.参考代码:

public ListNode detectCycle(){
        ListNode fast=this.head;
        ListNode slow=this.head;
        //先找到第一次相遇的时候
        while(fast!=null && fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
            if(fast==slow){
                break;
            }
        }
         if(fast==null || fast.next==null){
            return null;
        }
        //让slow或者fast到头那里
        slow=this.head;
        while(slow!=fast){
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }