📜  弗洛伊德循环寻找算法

📅  最后修改于: 2022-05-13 01:56:08.452000             🧑  作者: Mango

弗洛伊德循环寻找算法

Floyd 的循环查找算法或 Hare-Tortoise 算法是一种指针算法,它只使用两个指针,以不同的速度在序列中移动。该算法用于在链表中查找循环。它使用两个指针,其中一个的移动速度是另一个的两倍。较快的一个称为较快指针,另一个称为慢速指针。

Floyd 的循环查找算法如何工作?

在遍历链表时,会发生其中一件事情——

  • Fast 指针可能到达末尾(NULL),这表明链表中没有循环。
  • 快速指针在某个时间再次捕获慢速指针,因此链表中存在循环。

例子:

循环存在

伪代码:

  • 初始化两指针并开始遍历链表。
  • 将慢速指针移动一个位置。
  • 将快速指针移动两个位置。
  • 如果两个指针在某个点相遇,则存在循环,如果快速指针与结束位置相遇,则不存在循环。

下面是实现上述方法的 C++ 程序:

C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
class Node {
public:
    int data;
    Node* next;
 
    Node(int data)
    {
        this->data = data;
        next = NULL;
    }
};
 
// initialize a new head for the linked list
Node* head = NULL;
class Linkedlist {
public:
    // insert new value at the start
    void insert(int value)
    {
        Node* newNode = new Node(value);
        if (head == NULL)
            head = newNode;
        else {
            newNode->next = head;
            head = newNode;
        }
    }
 
    // detect if there is a loop
    // in the linked list
    bool detectLoop()
    {
        Node *slowPointer = head,
             *fastPointer = head;
 
        while (slowPointer != NULL
               && fastPointer != NULL
               && fastPointer->next != NULL) {
            slowPointer = slowPointer->next;
            fastPointer = fastPointer->next->next;
            if (slowPointer == fastPointer)
                return 1;
        }
 
        return 0;
    }
};
 
int main()
{
    Linkedlist l1;
    // inserting new values
    l1.insert(10);
    l1.insert(20);
    l1.insert(30);
    l1.insert(40);
    l1.insert(50);
 
    // adding a loop for the sake
    // of this example
    Node* temp = head;
    while (temp->next != NULL)
        temp = temp->next;
 
    temp->next = head;
 
    // loop added;
 
    if (l1.detectLoop())
        cout << "Loop exists in the"
             << " Linked List" << endl;
    else
        cout << "Loop does not exists "
             << "in the Linked List" << endl;
 
    return 0;
}


Java
// Java program to implement
// the above approach
 
import java.util.*;
 
class GFG{
 
static class Node {
    int data;
    Node next;
 
    Node(int data)
    {
        this.data = data;
        next = null;
    }
};
 
// initialize a new head for the linked list
static Node head = null;
static class Linkedlist {
    // insert new value at the start
    void insert(int value)
    {
        Node newNode = new Node(value);
        if (head == null)
            head = newNode;
        else {
            newNode.next = head;
            head = newNode;
        }
    }
 
    // detect if there is a loop
    // in the linked list
    boolean detectLoop()
    {
        Node slowPointer = head,
             fastPointer = head;
 
        while (slowPointer != null
               && fastPointer != null
               && fastPointer.next != null) {
            slowPointer = slowPointer.next;
            fastPointer = fastPointer.next.next;
            if (slowPointer == fastPointer)
                return true;
        }
 
    return false;
    }
}
 
public static void main(String[] args)
{
    Linkedlist l1 = new Linkedlist();
    // inserting new values
    l1.insert(10);
    l1.insert(20);
    l1.insert(30);
    l1.insert(40);
    l1.insert(50);
 
    // adding a loop for the sake
    // of this example
    Node temp = head;
    while (temp.next != null)
        temp = temp.next;
 
    temp.next = head;
 
    // loop added;
 
    if (l1.detectLoop())
        System.out.print("Loop exists in the"
            + " Linked List" +"\n");
    else
        System.out.print("Loop does not exists "
            + "in the Linked List" +"\n");
 
}
}
 
// This code is contributed by 29AjayKumar


Python3
# Python code for the above approach
class Node:
    def __init__(self, d):
        self.data = d
        self.next = None
 
# initialize a new head for the linked list
head = None
 
# detect if there is a loop
# in the linked list
def detectLoop(head):
    slowPointer = head
    fastPointer = head
 
    while (slowPointer != None
           and fastPointer != None
           and fastPointer.next != None):
        slowPointer = slowPointer.next
        fastPointer = fastPointer.next.next
        if (slowPointer == fastPointer):
            return 1
 
    return 0
 
# inserting new values
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head.next.next.next = Node(40)
head.next.next.next.next = Node(50)
 
# adding a loop for the sake
# of this example
temp = head
while (temp.next != None):
    temp = temp.next
 
temp.next = head
 
# loop added;
if (detectLoop(head)):
    print("Loop exists in the Linked List")
else:
    print("Loop does not exists in the Linked List")
 
# This code is contributed by Saurabh Jaiswal


C#
// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
public class GFG {
 
  public class Node {
    public int data;
    public Node next;
 
    public Node(int data) {
      this.data = data;
      next = null;
    }
  };
 
  // initialize a new head for the linked list
  static Node head = null;
 
  public class Linkedlist
  {
 
    // insert new value at the start
    public void insert(int value) {
      Node newNode = new Node(value);
      if (head == null)
        head = newNode;
      else {
        newNode.next = head;
        head = newNode;
      }
    }
 
    // detect if there is a loop
    // in the linked list
    public bool detectLoop() {
      Node slowPointer = head, fastPointer = head;
 
      while (slowPointer != null && fastPointer != null &&
             fastPointer.next != null)
      {
        slowPointer = slowPointer.next;
        fastPointer = fastPointer.next.next;
        if (slowPointer == fastPointer)
          return true;
      }
 
      return false;
    }
  }
 
  public static void Main(String[] args) {
    Linkedlist l1 = new Linkedlist();
    // inserting new values
    l1.insert(10);
    l1.insert(20);
    l1.insert(30);
    l1.insert(40);
    l1.insert(50);
 
    // adding a loop for the sake
    // of this example
    Node temp = head;
    while (temp.next != null)
      temp = temp.next;
 
    temp.next = head;
 
    // loop added;
    if (l1.detectLoop())
      Console.Write("Loop exists in the" + " Linked List" + "\n");
    else
      Console.Write("Loop does not exists " + "in the Linked List" + "\n");
 
  }
}
 
// This code is contributed by umadevi9616


Javascript


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
class Node {
public:
    int data;
    Node* next;
 
    Node(int data)
    {
        this->data = data;
        next = NULL;
    }
};
 
// intitalize a new head
// for the linked list
Node* head = NULL;
class Linkedlist {
public:
    // insert new value at the start
    void insert(int value)
    {
        Node* newNode = new Node(value);
        if (head == NULL)
            head = newNode;
        else {
            newNode->next = head;
            head = newNode;
        }
    }
 
    // detect if there is a loop
    // in the linked list
    Node* detectLoop()
    {
        Node *slowPointer = head,
             *fastPointer = head;
 
        while (slowPointer != NULL
               && fastPointer != NULL
               && fastPointer->next != NULL) {
            slowPointer = slowPointer->next;
            fastPointer = fastPointer->next->next;
            if (slowPointer == fastPointer)
                break;
        }
 
        // if no loop exists
        if (slowPointer != fastPointer)
            return NULL;
 
        // reset slow pointer to head
        // and traverse again
        slowPointer = head;
        while (slowPointer != fastPointer) {
            slowPointer = slowPointer->next;
            fastPointer = fastPointer->next;
        }
 
        return slowPointer;
    }
};
 
int main()
{
    Linkedlist l1;
    // inserting new values
    l1.insert(10);
    l1.insert(20);
    l1.insert(30);
    l1.insert(40);
    l1.insert(50);
 
    // adding a loop for the sake
    // of this example
    Node* temp = head;
    while (temp->next != NULL)
        temp = temp->next;
    // loop added;
    temp->next = head;
 
    Node* loopStart = l1.detectLoop();
    if (loopStart == NULL)
        cout << "Loop does not exists" << endl;
    else {
        cout << "Loop does exists and starts from "
             << loopStart->data << endl;
    }
 
    return 0;
}


输出
Loop exists in the Linked List

时间复杂度: O(n),因为循环遍历一次。
辅助空间: O(1),仅使用两个指针,因此空间复杂度恒定。

为什么弗洛伊德算法有效?

让我们考虑一个例子:

为什么弗洛伊德算法有效

  • 让,
  • 所以在两个指针相遇之前——
  • 由于快速指针的移动速度是慢速指针的两倍,我们可以说快速指针移动的距离是慢速指针移动距离的两倍。所以-                 
  • 现在,如果将慢速指针重新设置到头部(起始位置)并一次移动快慢指针一个单位,可以从第 1 和第 2 等式观察到,它们都会在开始移动 X 距离后相遇循环,因为在重置慢速指针并将其移动 X 距离后,同时从循环汇合点,快速指针也将行进 K * C - Y 距离(因为它已经行进了 Y 距离)。
  • 从等式 (2) 可以说 X = K * C - Y 因此,两个指针都将行进距离 X,即在某个点在粉红色节点之后的相同距离,以在循环的起点相遇。
  • 在这里,到某个时间点,这意味着快速指针可以完成它已经覆盖了 Y 距离的 K * C 距离。

下面是实现上述方法的 C++ 程序——

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
 
class Node {
public:
    int data;
    Node* next;
 
    Node(int data)
    {
        this->data = data;
        next = NULL;
    }
};
 
// intitalize a new head
// for the linked list
Node* head = NULL;
class Linkedlist {
public:
    // insert new value at the start
    void insert(int value)
    {
        Node* newNode = new Node(value);
        if (head == NULL)
            head = newNode;
        else {
            newNode->next = head;
            head = newNode;
        }
    }
 
    // detect if there is a loop
    // in the linked list
    Node* detectLoop()
    {
        Node *slowPointer = head,
             *fastPointer = head;
 
        while (slowPointer != NULL
               && fastPointer != NULL
               && fastPointer->next != NULL) {
            slowPointer = slowPointer->next;
            fastPointer = fastPointer->next->next;
            if (slowPointer == fastPointer)
                break;
        }
 
        // if no loop exists
        if (slowPointer != fastPointer)
            return NULL;
 
        // reset slow pointer to head
        // and traverse again
        slowPointer = head;
        while (slowPointer != fastPointer) {
            slowPointer = slowPointer->next;
            fastPointer = fastPointer->next;
        }
 
        return slowPointer;
    }
};
 
int main()
{
    Linkedlist l1;
    // inserting new values
    l1.insert(10);
    l1.insert(20);
    l1.insert(30);
    l1.insert(40);
    l1.insert(50);
 
    // adding a loop for the sake
    // of this example
    Node* temp = head;
    while (temp->next != NULL)
        temp = temp->next;
    // loop added;
    temp->next = head;
 
    Node* loopStart = l1.detectLoop();
    if (loopStart == NULL)
        cout << "Loop does not exists" << endl;
    else {
        cout << "Loop does exists and starts from "
             << loopStart->data << endl;
    }
 
    return 0;
}
输出
Loop does exists and starts from 50

时间复杂度: O(n),因为我们已经遍历循环一次,然后行进 X 距离。
辅助空间: O(1),因为只使用指针,因此空间复杂度恒定。