算法练习:判断单链表是否有环

题目就是如何判断一个单链表是否有环,也就是没有一个节点的next=null,这就是有环单链表

例如:无环单链表 e1>e2>e3>e4>e5>null

有环单链表 e1>e2>e3>e4>e5>e3 这里的e5节点又指向了e3节点,这就形成了环形链表。

判断方法有多种,如下三种方法思路:

方法1》》》1秒内不停的取链表节点的next,能取到next=null,说明无环,不能取到空,说明有环。
缺点:不准确,性能也不好。

方法2》》》没经过一个节点,就存到set中,每到一个节点就取set查找是否存在时间复杂度O(n)空间复杂度O(n) 。
缺点:占用O(n)的空间复杂度。

方法3》》》快慢指针(龟兔赛跑)
快指针每次走两步
慢指针每次走一步判断:
如果是环,快慢肯定相遇,相遇只是时间问题,时间复杂度是O(n)。
就好像两个人围着操场跑圈,一直跑,跑的快的一定会追上跑的慢的,这个就好比小学的应用题,两个人同时起跑,一快一慢,快的跑一圈60秒,慢的跑一圈90秒,问两人过了多长时间相遇。
缺点:不是常规思维,一开始可能不太好理解

快慢指针代码:

package com.example.demo.test;

class Element {
    String name;
    Element next;

    public Element(String name) {
        this.name = name;
    }

    public void setNext(Element next) {
        this.next = next;
    }

}

public class ReverseLinkedList {

    public static void main(String[] args) {
        Element e1 = new Element("e1");
        Element e2 = new Element("e2");
        Element e3 = new Element("e3");
        e1.setNext(e2);
        e2.setNext(e3);

        System.out.println("----反转前----");
        Element self = e1;
        while(self.next != null) {
            System.out.println(self.name + "的next:" +self.next.name);
            self = self.next;
        }

        reverseList(e1);
        System.out.println("----反转后----");
        Element self2 = e3;
        while(self2.next != null) {
            System.out.println(self2.name + "的next:" +self2.next.name);
            self2 = self2.next;
        }


    }

    public static void reverseList(Element head) {
        Element self = head;
        Element prev = null;

        while(self != null) {
            //这里只关注当前节点的前一个节点
            //而不需要在这里即设置当前节点的前一节点,也设置当前节点的下一节点的指向,
            //如果这样设置了,代码进入死循环,例如: self.next.next = self
            //而是在每一次循环中处理当前节点的前一节点
            Element next = self.next;//取出当前节点的next节点
            self.next = prev;//反转指针,当前节点的next节点指向前一节点
            prev = self;//更新前一节点指针,下次循环使用
            self = next;//当当前节点指向下一节点,准备接入下一次循环,来处理第二个节点的反转
        }
    }
}


输出结果为:true,demo中设置的数据确实是环形的。