数据结构单链表之检测和删除链表中的循环 | 第十三套

简介: 数据结构单链表之检测和删除链表中的循环 | 第十三套

编写一个函数detectAndRemoveLoop() 来检查给定的链表是否包含循环,如果存在循环,则删除循环并返回 true。如果列表不包含循环,则返回 false。下图显示了一个带有循环的链表。detectAndRemoveLoop() 必须将下面的列表更改为 1->2->3->4->5->NULL。

1.png

我们还建议阅读以下帖子作为此处讨论的解决方案的先决条件。编写一个 C 函数来检测链表中的循环 在尝试删除循环之前,我们必须检测它。上面帖子中讨论的技术可用于检测循环。要移除循环,我们需要做的就是获取指向循环最后一个节点的指针。例如,上图中值为 5 的节点。一旦我们有了指向最后一个节点的指针,我们就可以将这个节点的下一个节点设置为 NULL,循环就消失了。

我们可以轻松地使用哈希或访问节点技术(在上面提到的帖子中讨论过)来获取指向最后一个节点的指针。想法很简单:下一个已被访问(或散列)的第一个节点是最后一个节点。

我们也可以使用弗洛伊德循环检测算法来检测和删除循环。在弗洛伊德算法中,慢指针和快指针在循环节点相遇。我们可以使用这个循环节点来移除循环。当使用 Floyd 算法进行循环检测时,有以下两种不同的消除循环方法。

方法一(一一查) 我们知道,当快慢指针在一个公共点相遇时,弗洛伊德循环检测算法就终止了。我们也知道这个公共点是循环节点之一(上图中的 2 或 3 或 4 或 5)。将 this 的地址存储在一个指针变量中,比如 ptr2。之后,从链表的头部开始,一一检查节点是否可以从 ptr2 到达。每当我们找到一个可达的节点时,我们就知道这个节点是链表中循环的起始节点,我们可以得到这个节点的前一个节点的指针。

输出:

Linked List after removing loop 
50 20 15 4 10

方法二(更好的解决方案)  

  1. 该方法还依赖于 Floyd's Cycle 检测算法。
  2. 使用 Floyd 循环检测算法检测循环并获取指向循环节点的指针。
  3. 计算循环中的节点数。让计数为k。
  4. 将一个指针固定到头部,另一个指向头部的第 k 个节点。
  5. 以相同的速度移动两个指针,它们将在循环起始节点相遇。
  6. 获取指向循环最后一个节点的指针并将其下一个设为 NULL。
#include <bits/stdc++.h>
using namespace std;
struct Node {
  int data;
  struct Node* next;
};
void removeLoop(struct Node*, struct Node*);
int detectAndRemoveLoop(struct Node* list)
{
  struct 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) {
      removeLoop(slow_p, list);
      /* Return 1 to indicate that loop is found */
      return 1;
    }
  }
  return 0;
}
void removeLoop(struct Node* loop_node, struct Node* head)
{
  struct Node* ptr1 = loop_node;
  struct Node* ptr2 = loop_node;
  unsigned int k = 1, i;
  while (ptr1->next != ptr2) {
    ptr1 = ptr1->next;
    k++;
  }
  ptr1 = head;
  ptr2 = head;
  for (i = 0; i < k; i++)
    ptr2 = ptr2->next;
  while (ptr2 != ptr1) {
    ptr1 = ptr1->next;
    ptr2 = ptr2->next;
  }
  while (ptr2->next != ptr1)
    ptr2 = ptr2->next;
  ptr2->next = NULL;
}
void printList(struct Node* node)
{
  while (node != NULL) {
    cout << node->data << " ";
    node = node->next;
  }
}
struct Node* newNode(int key)
{
  struct Node* temp = new Node();
  temp->data = key;
  temp->next = NULL;
  return temp;
}
int main()
{
  struct Node* head = newNode(50);
  head->next = newNode(20);
  head->next->next = newNode(15);
  head->next->next->next = newNode(4);
  head->next->next->next->next = newNode(10);
  head->next->next->next->next->next = head->next->next;
  detectAndRemoveLoop(head);
  cout << "Linked List after removing loop \n";
  printList(head);
  return 0;
}

输出:

Linked List after removing loop 
50 20 15 4 10 


目录
相关文章
|
3天前
|
存储
数据结构第二课 -----线性表之单向链表
数据结构第二课 -----线性表之单向链表
|
3天前
|
存储
数据结构第三课 -----线性表之双向链表
数据结构第三课 -----线性表之双向链表
|
4天前
|
存储 Java
数据结构奇妙旅程之顺序表和链表
数据结构奇妙旅程之顺序表和链表
|
6天前
|
算法 索引
数据结构与算法-循环链表详解
数据结构与算法-循环链表详解
6 0
|
6天前
|
算法 Java C语言
数据结构与算法-双向链表知识详解
数据结构与算法-双向链表知识详解
5 0
|
6天前
|
算法 数据可视化 Java
数据结构与算法-单向链表的实现以及相关面试题
数据结构与算法-单向链表的实现以及相关面试题
7 0
|
8天前
|
存储 C语言
数据结构基础:双链表结构、实现
数据结构基础:双链表结构、实现
|
8天前
|
存储
数据结构基础:一篇文章教你单链表(头插,尾插,查找,头删等的解析和代码)
数据结构基础:一篇文章教你单链表(头插,尾插,查找,头删等的解析和代码)
|
11天前
|
C语言
数据结构:5、链表之双向链表
数据结构:5、链表之双向链表
25 0
|
11天前
|
存储
数据结构:4、链表之单链表
数据结构:4、链表之单链表
11 0