Detect Cycle in a linked list (Floyd’s Cycle Detection Algorithm)

来源:互联网 发布:北京现代软件学院骗局 编辑:程序博客网 时间:2024/05/21 08:02

Detect Cycle in a linked list(Floyd’s Cycle Detection Algorithm)

给定一个链表,检测其中的周期。

例如,下面的链表有一个循环

循环链表

使用哈希

简单的解决方案是使用散列。这个想法是遍历给定的列表,并将每个遇到的节点插入到一个集合中。现在,如果当前节点已经存在于集合中(即前面看到的),则表示列表中存在一个周期。

C ++实现 -

#include <iostream>#include <unordered_set>using namespace std;//数据结构存储链表节点struct Node{    int data;    Node* next;};// Helper函数用给定的数据创建一个新节点//将其推到列表的前面void push(Node*& headRef, int data){     //从堆创建一个新的链表节点    Node* newNode = new Node;    newNode->data = data;    newNode->next = headRef;    headRef = newNode;}//使用哈希来检测链表中的循环的功能bool detectCycle(Node *head){    Node *curr = head;    unordered_set<Node*> set;    //遍历列表    while (curr)    {        //如果我们以前已经看过这个节点,则返回false        if (set.find(curr) != set.end())            return true;         //将当前节点插入到集合中        set.insert(curr);         //移动到下一个节点        curr = curr->next;    }    //我们到达这里,如果列表不包含任何循环返回假    return false;}// main方法int main(){     //输入键    int keys[] = { 1, 2, 3, 4, 5 };    int n = sizeof(keys) / sizeof(keys[0]);    Node* head = nullptr;    for (int i = n - 1; i >= 0; i--)        push(head, keys[i]);     //插入循环    head->next->next->next->next->next = head->next->next;    if (detectCycle(head))        cout << "Cycle Found";    else        cout << "No Cycle Found";    return 0;}
输出:
Cycle Found

上述解的时间复杂度为O(n),程序使用的辅助空间为O(n)。

弗洛伊德的循环查找算法

Floyd的循环查找算法是一种仅使用两个指针的指针算法,它们以不同的速度移动序列。这个想法是将快速指针快速移动到慢指针的两倍,并且它们之间的距离在每一步增加1。如果在某个时候两者都相遇,我们在列表中找到了一个循环,否则如果我们已经到了列表的末尾,就没有循环。它也被称为“乌龟和野兔算法”。

C++ implementation –

#include <iostream>#include <unordered_set>using namespace std;//数据结构存储链表节点list nodestruct Node{    int data;    Node* next;};// Helper函数用给定的数据创建一个新节点//将其推到列表的前面void push(Node*& headRef, int data){    //从堆创建一个新的链表节点    Node* newNode = new Node;    newNode->data = data;    newNode->next = headRef;    headRef = newNode;}//使用Floyd?循环检测链表中的循环的功能//检测算法bool detectCycle(Node *head){    //取两个指针     Node *slow = head, *fast = head;    while (fast && fast->next)    {        // 通过一个指针移动        slow = slow->next;         //用两个指针快速移动        fast = fast->next->next;         //如果他们遇到任何节点,链表包含一个循环        if (slow == fast)           return true;    }     //我们到达这里,如果慢&快指针不符合    return false;}// main方法int main(){     //输入键    int keys[] = { 1, 2, 3, 4, 5 };    int n = sizeof(keys) / sizeof(keys[0]);    Node* head = nullptr;    for (int i = n - 1; i >= 0; i--)        push(head, keys[i]);     //插入循环    head->next->next->next->next->next = head->next->next;    if (detectCycle(head))        cout << "Cycle Found";    else        cout << "No Cycle Found";    return 0;}
输出:
Cycle Found

上述解的时间复杂度为O(n),程序使用的辅助空间为O(1)。