Java determines whether the linked list has a ring (implemented in two ways)

Time:2022-5-14

Judge whether the linked list is a linked list

Method 1: judge whether the pointer moves fast or slow

First, how to judge whether the linked list has rings? At this time, you first need to know whether the linked list is empty. If it is not empty, continue to judge.

Idea: first define two variables, one fast and one slow. Let fast take two steps at a time and slow take one step at a time. When fast and slow meet, there is a ring structure in the linked list. If the linked list is an acyclic structure, it will not meet when traversing the linked list. That is, false is returned.

The legend is as follows:
To illustrate the situation,
The fast pointer is initially marked as F0, and 1 is added every time it moves, such as F1, F2, F3
The slow pointer is initially marked as S0, and 1 is added every time it moves, such as S1, S2, S3

Java determines whether the linked list has a ring (implemented in two ways)

5660a8da20b37b4a5a820604efb8205.png

The code implementation is as follows:

//Initialize a linked list node with a ring
Node nodeA = new Node("A");
Node nodeB = new Node("B");
Node nodeC = new Node("C");
Node nodeD = new Node("D");
Node nodeE = new Node("E");
Node nodeF = new Node("F");

nodeA.next = nodeB;
nodeB.next = nodeC;
nodeC.next = nodeD;
nodeD.next = nodeE;
nodeE.next = nodeF;
nodeF. next = nodeD;// At this time, node f points to node D, and a ring has been generated
/**
     *Judge whether the linked list has a ring (the way of fast and slow pointer)
     *                                       <-----------------
     *                                      |                 |
     *          [A]  ->  [B]  ->  [C]  ->  [D]  ->  [E]  ->  [F]
     *
     *Initial pointer F0
     *          s0
     *First S1 F1
     *Second S2 F2
     *Third S3 / F3
     *In this example, the third traversal determines that there are links in the linked list
     * @param node
     * @return
     */
    private boolean hasCycle(Node node) {
        if (node == null) {
            return false;
        }
        Node fast = node;
        Node slow = node;
        //This field is only used to record the number of iterations
        int traverseCount = 0;
        while (fast != null && fast.next != null && slow != null) {
            fast = fast. next. next;// Move 2 steps
            slow = slow. next;// Move 1 step
            traverseCount ++;
            if (fast == slow) {
                //If we meet, it means there is a ring
                Log. D (tag, "hascycle = = > looped... Traversecount =" + traversecount);
                return true;
            }
            Log. D (tag, "hascycle = = > traversal times... Traversecount =" + traversecount);
        }
        Log. D (tag, "hascycle = = > acyclic");
        return false;
    }

Method 2: use the set < > set to record node elements. If there are duplicate elements, it is considered that there are rings
The code implementation is as follows:

/**
     *If there is duplicate data, it means that there is a ring through the way of set recording values
     * @param node
     * @return
     */
    private boolean hasCycle2(Node node) {
        Set<Node> nodeSet = new HashSet<>();
        //This field is only used to record the number of iterations
        int traverseCount = 0;
        while (node != null) {
            if (nodeSet.contains(node)) {
                Log. D (tag, "hascycle2 = = > looped... Traversecount =" + traversecount);
                return true;
            }
            traverseCount ++;
            Log.d(TAG, "hasCycle2==>traverseCount="+traverseCount);
            nodeSet.add(node);
            node = node.next;
        }
        Log. D (tag, "hascycle2 = = > acyclic");
        return false;
    }

3、 Extension: (content reference:https://blog.csdn.net/weixin_40879743/article/details/90646399
If there are links in the linked list, find which node is the entry point of the link (as shown in the figure above, the entry point is node D, which is to be found below)
Train of thought: S = VT (distance = speed * time) use equation idea to formulate equation solution
Because the distance is known, the speed is known (double relation), and the time is also known (equal relation), the relation can be solved by equation. Then use the code to reflect the relationship, you can solve this problem.

As shown in the figure: suppose the linked list is link, fast is the fast pointer, slow is the slow pointer, blue is the distance fast has traveled, and green is the distance slow has traveled

K is the entrance of the ring, and P is the place where the fast and slow pointers meet
a. B and C represent the length of three sections respectively.

Java determines whether the linked list has a ring (implemented in two ways)

image.png

So the diagram can become:

Java determines whether the linked list has a ring (implemented in two ways)

image.png

Then, let the pointer traverse from the meeting point P and the starting point first at the same time. In this way, since C = a, P and first meet at K, and K is the entry point.

The code implementation is as follows:

/**
     *If there is a ring, obtain the node of the meeting point
     * @param node
     * @return
     */
    private Node getMeetNode(Node node) {
        if (node == null) {
            return null;
        }
        Node fast = node;
        Node slow = node;
        //This field is only used to record the number of iterations
        int traverseCount = 0;
        while (fast != null && fast.next != null && slow != null) {
            fast = fast. next. next;// Move 2 steps
            slow = slow. next;// Move 1 step
            traverseCount ++;
            if (fast == slow) {
                //If we meet, it means there is a ring
                Log. D (tag, "hascycle = = > looped... Traversecount =" + traversecount);
                return fast;
            }
            Log. D (tag, "hascycle = = > traversal times... Traversecount =" + traversecount);
        }
        return null;
    }

    /**
     *If there is a ring, obtain the entry point where the ring appears
     * @return
     */
    public Node getCycleEntry(Node node) {
        Node meetNode = getMeetNode(node);
        Node p = meetNode;// Pointer to the meeting point element
        Node first = node;// Pointer to the first element of the linked list
        while(p != first) {
            //Both pointers move, and when they are equal, the entry point is found
            first = first.next;
            p = p.next;
        }
        return p;
    }

   /**
    *Print the entry point:
    */
    Node entryNode = getCycleEntry(nodeA);
    Log. D (tag, "linked list entry point node value =" + entrynode. Value);