C++程序 检测链表中的循环
给定一个链表,检查它是否存在循环。下面的图示展示了带有循环的链表。
以下是不同的实现方法。
解法 1:哈希方法:
逐一遍历列表,将节点地址放入哈希表中。若到达 NULL 则返回 false,若当前节点的下一个指向哈希表中已经存储的任意一个节点,则返回 true。
输出
复杂度分析:
- 时间复杂度: O(n)。 只需要一次遍历循环。
- 辅助空间: O(n)。 n 是哈希表所需的空间。
解法 2: 可以通过修改链表数据结构来解决此问题,不需要使用哈希表。
做法: 此解决方法需要修改基本链表数据结构。
- 对每个节点,添加一个已访问标记。
- 遍历链表并标记已访问的节点。
- 如果再次遇到已标记的节点,则存在循环。这种解法的时间复杂度为 O(n),但需要在每个节点上添加额外信息。
- 这种方法的一种变体,不需要修改基本数据结构,可以通过哈希表实现。只需在哈希表中存储已访问节点的地址,并且如果看到哈希表中已经存在的地址,则存在循环。
输出
复杂度分析:
- 时间复杂度: O (n)。 仅需要一次遍历循环。
- 辅助空间: O (1)。 不需要额外的空间。
解决方案3:Floyd的循环查找算法
方法: 这是最快的方法,如下所述:
- 使用两个指针遍历链表。
- 将一个指针(slow_p)移动一步,另一个指针(fast_p)移动两步。
- 如果这些指针在同一节点相遇,则存在循环。如果指针不相遇,则链表没有循环。
以下图像显示了代码中的detectloop函数的工作方式:
Floyd循环查找算法的实现:
输出
时间/空间复杂度分析:
- 时间复杂度: O(n)。 只需要一次遍历循环。
- 空间复杂度: O(1)。 不需要额外空间。
解决方案4:标记访问但不修改链接列表结构的节点
在此方法中,创建一个临时节点。将要遍历的每个节点的下一个指针指向此临时节点。通过这种方式,我们使用节点的下一个指针作为标志来指示节点是否已遍历。检查每个节点以查看下一个指向临时节点还是不指向。对于循环的第一个节点,在第二次遍历它时,这个条件将为真,因此我们发现存在循环。如果遇到指向空的节点,则不存在循环。
以下是上述方法的实现:
输出
复杂度分析:
- 时间复杂度: O(n)。 只需要一次遍历循环。
- 辅助空间: O(1)。 不需要额外的空间。
解决方案5:存储长度
在此方法中,创建两个指针,第一个始终指向头,第二个始终指向末尾。每次最后一个指针移动时,我们计算第一个和最后一个之间的节点数,并检查当前节点数是否大于先前节点数,如果是,则进行下一步移动最后一个指针,否则它意味着我们已经到达了循环的结尾,因此返回相应的输出。
输出
复杂度分析:
- 时间复杂度: O(n2)
- 辅助空间: O(1)
其他方法:
- 这是给定问题的最简单方法,我们所要做的就是为链接列表中每个节点的数据分配一个新值,该值不在给定范围内。
- 例如,假设(1<=Data on Node<=10^3),则在访问节点后,将数据分配为-1,因为它超出了给定范围。
请按以下给出的代码进行更好的理解:
输出
时间复杂度: O(N)
辅助空间: O(1)