C语言/C++学习之C++中检测链表中的循环
小职 2020-12-30 来源 : 阅读 722 评论 0

摘要:C语言/C++学习之C++中检测链表中的循环:本文主要总结了五个C++中检测链表中的循环的办法,通过具体的内容向大家展现,希望对C语言/C++的学习有所帮助。

C语言/C++学习之C++中检测链表中的循环:本文主要总结了五个C++中检测链表中的循环的办法,通过具体的内容向大家展现,希望对C语言/C++的学习有所帮助。

C语言/C++学习之C++中检测链表中的循环


给定一个链表,检查链表是否有循环。下图显示了带有循环的链表。

 C语言/C++学习之C++中检测链表中的循环

五个解决办法教你C++中检测链表中的循环

以下是执行此操作的不同方法

 

解决方案1:散列方法:

 

遍历该列表,并将节点地址始终放在哈希表中。在任何时候,如果达到NULL,则返回false,如果当前节点的下一个指向Hash中先前存储的任何节点,则返回true。

 

#include <bits/stdc++.h>

using namespace std;

struct Node {

    int data;

    struct Node* next;

};

  

void push(struct Node** head_ref, int new_data)

{

    struct Node* new_node = new Node;

    new_node->data = new_data;

    new_node->next = (*head_ref);

    (*head_ref) = new_node;

}

bool detectLoop(struct Node* h)

{

    unordered_set<Node*> s;

    while (h != NULL) {

        if (s.find(h) != s.end())

            return true;

        s.insert(h);

  

        h = h->next;

    }

  

    return false;

}

int main()

{

    struct Node* head = NULL;

  

    push(&head, 20);

    push(&head, 4);

    push(&head, 15);

    push(&head, 10);

    head->next->next->next->next = head;

  

    if (detectLoop(head))

        cout << "Loop found";

    else

        cout << "No Loop";

  

    return 0;

}

复杂度分析:

 

时间复杂度: O(n)。

只需循环一次即可。

 

辅助空间: O(n)。

n是将值存储在哈希图中所需的空间。

 

解决方案2:通过修改链表数据结构,无需哈希图即可解决此问题。

方法:此解决方案需要修改基本链表数据结构。

 

每个节点都有一个访问标志。

遍历链接列表并继续标记访问的节点。

如果您再次看到一个访问过的节点,那么就会有一个循环。该解决方案适用于O(n),但每个节点都需要其他信息。

此解决方案的一种变体不需要修改基本数据结构,可以使用哈希来实现,只需将访问的节点的地址存储在哈希中,如果您看到哈希中已经存在的地址,则存在一个循环。

C++:

 

#include <bits/stdc++.h>

using namespace std;

struct Node {

    int data;

    struct Node* next;

    int flag;

};

  

void push(struct Node** head_ref, int new_data)

{

    struct Node* new_node = new Node;

    new_node->data = new_data;

  

    new_node->flag = 0;

    new_node->next = (*head_ref);

    (*head_ref) = new_node;

}

bool detectLoop(struct Node* h)

{

    while (h != NULL) {

        if (h->flag == 1)

            return true;

        h->flag = 1;

  

        h = h->next;

    }

  

    return false;

}

int main()

{

    struct Node* head = NULL;

  

    push(&head, 20);

    push(&head, 4);

    push(&head, 15);

    push(&head, 10);

    head->next->next->next->next = head;

  

    if (detectLoop(head))

        cout << "Loop found";

    else

        cout << "No Loop";

  

    return 0;

}

复杂度分析:

 

时间复杂度: O(n)。

只需循环一次即可。

 

辅助空间: O(1)。

不需要额外的空间。

 

解决方案3:Floyd的循环查找算法

方法:这是最快的方法,下面进行了介绍:

 

使用两个指针遍历链表。

将一个指针(slow_p)移动一个,将另一个指针(fast_p)移动两个。

如果这些指针在同一节点相遇,则存在循环。如果指针不符合要求,则链接列表没有循环。

Floyd的循环查找算法的实现:

 

#include <bits/stdc++.h>

using namespace std;

class Node {

public:

    int data;

    Node* next;

};

  

void push(Node** head_ref, int new_data)

{

    Node* new_node = new Node();

    new_node->data = new_data;

    new_node->next = (*head_ref);

    (*head_ref) = new_node;

}

  

int detectLoop(Node* list)

{

    Node *slow_p = list, *fast_p = list;

  

    while (slow_p && fast_p && fast_p->next) {

        slow_p = slow_p->next;

        fast_p = fast_p->next->next;

        if (slow_p == fast_p) {

            return 1;

        }

    }

    return 0;

}

int main()

{

    Node* head = NULL;

  

    push(&head, 20);

    push(&head, 4);

    push(&head, 15);

    push(&head, 10);

    head->next->next->next->next = head;

    if (detectLoop(head))

        cout << "Loop found";

    else

        cout << "No Loop";

    return 0;

}

解决方案4:在不修改链接列表数据结构的情况下标记访问的节点

在此方法中,将创建一个临时节点。使遍历的每个节点的下一个指针指向该临时节点。这样,我们将节点的下一个指针用作标志来指示该节点是否已遍历。检查每个节点以查看下一个节点是否指向临时节点。在循环的第一个节点的情况下,第二次遍历该条件将成立,因此我们发现该循环存在。如果遇到一个指向null的节点,则循环不存在。

下面是上述方法的实现:

 

#include <bits/stdc++.h>

using namespace std;

  

struct Node {

    int key;

    struct Node* next;

};

  

Node* newNode(int key)

{

    Node* temp = new Node;

    temp->key = key;

    temp->next = NULL;

    return temp;

}

void printList(Node* head)

{

    while (head != NULL) {

        cout << head->key << " ";

        head = head->next;

    }

    cout << endl;

}

bool detectLoop(Node* head)

{

    Node* temp = new Node;

    while (head != NULL) {

        if (head->next == NULL) {

            return false;

        }

        if (head->next == temp) {

            return true;

        }

        Node* nex = head->next;

        head->next = temp;

        head = nex;

    }

  

    return false;

}

int main()

{

    Node* head = newNode(1);

    head->next = newNode(2);

    head->next->next = newNode(3);

    head->next->next->next = newNode(4);

    head->next->next->next->next = newNode(5);

    head->next->next->next->next->next = head->next->next;

  

    bool found = detectLoop(head);

    if (found)

        cout << "Loop Found";

    else

        cout << "No Loop";

  

    return 0;

}

复杂度分析:

 

时间复杂度: O(n)。

只需循环一次即可。

 

辅助空间: O(1)。

不需要空间。

 

解决方案5:存放长度

 

在此方法中,将创建两个指针,第一个(始终指向头)和最后一个指针。每次最后一个指针移动时,我们都会计算第一个和最后一个之间的节点数,并检查当前节点数是否大于先前的节点数,如果是,我们通过移动最后一个指针进行操作,否则就意味着我们已经到达循环的终点,因此我们相应地返回输出。

 

#include <bits/stdc++.h>

using namespace std;

  

struct Node {

    int key;

    struct Node* next;

};

  

Node* newNode(int key)

{

    Node* temp = new Node;

    temp->key = key;

    temp->next = NULL;

    return temp;

}

void printList(Node* head)

{

    while (head != NULL) {

        cout << head->key << " ";

        head = head->next;

    }

    cout << endl;

}

int distance(Node* first, Node* last)

{

    int counter = 0;

  

    Node* curr;

    curr = first;

  

    while (curr != last) {

        counter += 1;

        curr = curr->next;

    }

  

    return counter + 1;

}

bool detectLoop(Node* head)

    Node* temp = new Node;

  

    Node *first, *last;

    first = head;

    last = head;

    int current_length = 0;

    int prev_length = -1;

  

    while (current_length > prev_length && last != NULL) {

          prev_length = current_length;

        current_length = distance(first, last);

        last = last->next;

    }

      

    if (last == NULL) {

        return false;

    }

    else {  

        return true;

    }

}

int main()

{

    Node* head = newNode(1);

    head->next = newNode(2);

    head->next->next = newNode(3);

    head->next->next->next = newNode(4);

    head->next->next->next->next = newNode(5);

    head->next->next->next->next->next = head->next->next;

  

    bool found = detectLoop(head);

    if (found)

        cout << "Loop Found";

    else

        cout << "No Loop Found";

  

    return 0;

}



关注“职坐标在线”(Zhizuobiao_Online)公众号,免费获取学习视频资料、技术就业咨询

C语言/C++学习之C++中检测链表中的循环

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程