检测单链表是否有环

/**
 * 单链表中环的检测、环的长度、环的入口结点、环前长度
 * <p>
 * 思路:快慢指针,慢指针每次前进一个结点,快指针每次前进两个结点,如果两个指针相遇,则说明有环;
 * 两指针相遇后,记录相遇结点,慢指针继续前进,同时记录步数,直到再次到相遇结点,前进的步数为环的长度;
 * 求得环的长度后,再次采用快慢指针从头遍历,快指针先前进n个结点(n为环的长度),之后两个结点一起前进,两指针相遇的结点即为环的入口;
 * 再次从头结点遍历,到环的入口之间的结点经历的结点个数,即为环前长度。
 */
public class CircleCheck {


    /**
     * 判断链表是否有环
     */
    static boolean hasCircle(Node list) {
        //空链表返回false
        if (list == null) {
            return false;
        }
        Node fast = list;
        Node slow = list;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                //两个指针相遇,证明有环
                return true;
            }
        }
        return false;
    }

    /**
     * 判断链表是否有环,如果有则返回快慢指针相遇结点
     */
    private static Node hasCircleReturnNode(Node list) {
        //空链表返回false
        if (list == null) {
            return null;
        }
        Node fast = list;
        Node slow = list;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                //两个指针相遇,证明有环
                return slow;
            }
        }
        return null;
    }


    /**
     * 求链表中环的长度
     */
    static int circleLength(Node list) {
        Node p = hasCircleReturnNode(list);
        if (p == null) {
            //无环返回0
            return 0;
        }
        int length = 0;
        Node n = p;
        do {
            n = n.next;
            length++;
        } while (n != p);
        return length;
    }

    /**
     * 求链表中环的入口结点
     * @param list
     * @return
     */
    static Node circleEntrance(Node list) {
        int circleLength = circleLength(list);
        if (circleLength == 0) {
            return null;
        }

        Node slow = list;
        Node fast = list;

        for (int i = 0; i < circleLength; i++) {
            fast = fast.next;
        }

        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }


    /**
     * 求链表的环前长度,如果无环返回链表总长度
     * @param list
     * @return
     */
    public static int lengthBeforeCircleEntrance(Node list) {
        Node entrance = circleEntrance(list);

        Node p = list;
        int length = 0;
        while (p != entrance) {
            length++;
            p = p.next;
        }
        return length;
    }
}

最后更新于

这有帮助吗?