floyd算法 每一层循环
In this tutorial, we’ll be discussing a very popular algorithm which is used to detect whether a LinkedList has loops. It’s called Floyd’s Cycle-Finding Algorithm.
在本教程中,我们将讨论一种非常流行的算法,该算法用于检测LinkedList是否具有循环。 它被称为弗洛伊德的循环发现算法。
A loop exists in a LinkedList when no NULL is reached as we traverse throughout the LinkedList.
当遍历整个LinkedList时没有到达NULL时,LinkedList中存在一个循环。
So in order to detect whether a LinkedList has a loop or not, we can traverse through the LinkedList and add each Node to the HashSet of visited notes if it’s been visited for the first item.
Once we reach a node that’s already present in the HashSet we can tell that there was a loop.
因此,为了检测LinkedList是否具有循环,我们可以遍历LinkedList,并将每个Node添加到已访问笔记的HashSet(如果已访问第一项)。
一旦我们到达HashSet中已经存在的节点,我们就可以知道存在一个循环。
But this approach, though simpler takes up extra space.
但是这种方法虽然更简单,但会占用额外的空间。
Another way is to set a flag for the visited nodes in the LinkedList Node data itself. But again, this approach would take some additional space. More than what we used earlier.
另一种方法是在LinkedList节点数据本身中为访问的节点设置标志。 但是同样,这种方法会占用一些额外的空间。 比我们之前使用的更多。
Hence, the ideal approach to detect a loop is using Floyd’s Cycle-Finding Algorithm
因此,检测环路的理想方法是使用弗洛伊德的循环查找算法
Floyd’s Cycle-Finding Algorithm uses two pointers that move at different speeds. If there is a cycle, both of the pointers would point to the same value at some point in the future.
弗洛伊德的循环查找算法使用两个以不同速度移动的指针。 如果存在一个周期,则两个指针将来都将指向相同的值。
Floyd’s Cycle-Finding Algorithm is similar to the Tortoise Hair Story.
Floyd的循环查找算法类似于乌龟的头发故事。
Let’s write the Java Program to create our own LinkedList class.
让我们编写Java程序来创建我们自己的LinkedList类。
MyLinkedList.java
MyLinkedList.java
package com.journaldev.linkedlist.reverse;
/**
* A very simple linked list implementation
* Not to use in application, created to show the linked list
* operations, hence very minimal features
*
* @author pankaj
*
*/
public class MyLinkedList {
public Node head;
public static class Node {
public Node next;
public Object data;
public Node(Object data) {
this.data = data;
next = null;
}
}
}
The following class contains the method to detect a loop in the LinkedList.
下列类包含检测LinkedList中的循环的方法。
package com.journaldev.linkedlist.loopDetection;
import com.journaldev.linkedlist.reverse.MyLinkedList;
import com.journaldev.linkedlist.reverse.MyLinkedList.Node;
public class DetectLinkedListLoop {
public static void main(String[] args) {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.head = new Node(1);
myLinkedList.head.next = new Node(2);
Node node = myLinkedList.head.next.next = new Node(3);
myLinkedList.head.next.next.next = new Node(4);
myLinkedList.head.next.next.next.next = new Node(5);
myLinkedList.head.next.next.next.next.next = node;
System.out.println("Has Loop? " + hasLoop(myLinkedList));
}
private static boolean hasLoop(MyLinkedList myLinkedList) {
Node head = myLinkedList.head;
Node slow = head;
Node fast = head;
boolean loop = false;
while (slow != null && fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
loop = true;
break;
}
}
return loop;
}
}
We’ve moved the fast pointer at twice the speed of the slow pointer.
If there is a loop, at some point the fast and slow pointer would meet. Here we can end the while statement and return the boolean flag.
我们以快慢指针两倍的速度移动了快指针。
如果存在循环,则快指针和慢指针有时会相遇。 在这里,我们可以结束while语句并返回布尔值标志。
The above code returns a true
.
上面的代码返回true
。
In order to detect the starting node of the Loop, we need to add another step to the above Algorithm.
为了检测循环的起始节点,我们需要在上述算法中增加另一步。
private static Node startNode(MyLinkedList myLinkedList) {
Node head = myLinkedList.head;
Node slow = head;
Node fast = head;
boolean loop = false;
while (slow != null && fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
loop = true;
break;
}
}
if (loop) {
slow = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
} else {
return new Node(Integer.MIN_VALUE);
}
}
Call the above method in the main
:
在main
调用上述方法:
System.out.println("Start Node data: " + startNode(myLinkedList).data);
This will return the Node with the data 3.
这将返回带有数据的节点3。
Once we’ve found the starting point of the loop, we can keep a pointer there and traverse the other pointer through the nodes while incrementing the length by 1.
找到循环的起点后,我们可以在其中保留一个指针,并通过节点将另一个指针遍历,同时将长度增加1。
private static int lengthOfLoop(MyLinkedList myLinkedList) {
Node head = myLinkedList.head;
Node slow = head;
Node fast = head;
boolean loop = false;
while (slow != null && fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
loop = true;
break;
}
}
if (loop) {
int length = 0;
slow = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
do {
fast = fast.next;
length++;
} while (fast != slow);
return length;
}
return 0;
}
Call the above method in the main
:
在main
调用上述方法:
System.out.println("Length of loop: " + lengthOfLoop(myLinkedList));
The length of the loop in the above example is 3.
上例中的循环长度为3。
In order to remove the loop, we need to add another step to the above example:
为了删除循环,我们需要在上面的示例中添加另一个步骤:
That fast pointer’s current position would be the last node of the loop. We need to set the next
of that node as null.
该快速指针的当前位置将是循环的最后一个节点。 我们需要将该节点的next
设置为null。
private static Node removeLoop(MyLinkedList myLinkedList) {
Node head = myLinkedList.head;
Node slow = head;
Node fast = head;
boolean loop = false;
while (slow != null && fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
loop = true;
break;
}
}
if (loop) {
slow = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
while (fast.next != slow) {
fast = fast.next;
}
fast.next = null;
return head;
}
return head;
}
Call the above method in the main
:
在main
调用上述方法:
myLinkedList.head = removeLoop(myLinkedList);
System.out.println("Has Loop? " + hasLoop(myLinkedList));
The complete output is:
完整的输出为:
Floyd’s Cycle-Finding Algorithm
弗洛伊德的循环发现算法
Time Complexity: O(n)
Auxiliary Space: O(1)
时间复杂度:O(n)
辅助空间:O(1)
That brings an end to this tutorial.
这样就结束了本教程。
翻译自: https://www.journaldev.com/23049/linked-list-loop-detection-floyds-cycle-finding-algorithm
floyd算法 每一层循环