Java 检测链表中的循环
首先,我应该提到,我已经检查并理解了最流行的检测链表中是否有循环的算法(谈论这个) 然而,我试着实现我自己的想法,它似乎在我的例子中起作用——但是它在执行时间上失败了,这让我认为它可以以某种方式进入一个无限循环 我的问题是:我需要知道我的代码是否正确,或者在某些情况下确实进入无限循环 这是单链表的定义Java 检测链表中的循环,java,linked-list,infinite-loop,circular-reference,Java,Linked List,Infinite Loop,Circular Reference,首先,我应该提到,我已经检查并理解了最流行的检测链表中是否有循环的算法(谈论这个) 然而,我试着实现我自己的想法,它似乎在我的例子中起作用——但是它在执行时间上失败了,这让我认为它可以以某种方式进入一个无限循环 我的问题是:我需要知道我的代码是否正确,或者在某些情况下确实进入无限循环 这是单链表的定义 class ListNode { int val; ListNode next; ListNode(int x) { val = x; next =
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
这就是功能:
public boolean hasCycle(ListNode head) {
//create a list that will contain the elements that have been visited
List<ListNode> ref = new ArrayList<ListNode>();
ListNode element = head;
//add the first element to the list
ref.add(head);
boolean contains = false;
//the special case when the linkedlist is empty
if(head==null)
return false;
while(contains == false){
if(element.next!=null && !ref.contains(element.next)){
ref.add(element.next);
element = element.next;
contains = false;
}
else if (ref.contains(element.next))
contains = true;
else if(element.next == null)
return false;
}
return contains;
}
public boolean hasCycle(列表节点头){
//创建一个包含已访问元素的列表
List ref=new ArrayList();
ListNode元素=头;
//将第一个元素添加到列表中
参考添加(标题);
布尔包含=假;
//linkedlist为空时的特殊情况
if(head==null)
返回false;
while(contains==false){
if(element.next!=null&&!ref.contains(element.next)){
参考添加(元素下一步);
element=element.next;
包含=假;
}
else if(参考包含(元素下一步))
包含=真;
else if(element.next==null)
返回false;
}
返回包含;
}
我认为您的代码不可能进入无限循环。以下是算法的可能控制流:
- 如果head为null,则返回false。头部为空现在是一个不变量
- 如果头部的下一个节点是自身,则返回false。head被预先添加到已访问元素的集合中,这使得它变得微不足道
- 如果当前节点的下一个节点为非空且以前未访问过,请将其添加到已访问节点列表中并继续执行
- 如果当前节点的下一个节点为非空,但以前访问过,请执行(现在是多余的)检查以确保该节点以前确实访问过。此时,我们保证在列表中有一个循环,因此我们返回true
- 如果当前节点的下一个节点为空,请检查以前是否访问过任何空节点。由于我们的不变量,头部一开始不是空的,所以无法到达这个特定的分支
- 执行(现在是多余的)检查以查看当前节点的下一个节点是否为空。此时,可以保证当前元素的下一个元素为null,这样就很容易得出结论:在完全遍历列表时,没有遇到循环,并且返回false是安全的
此外,如果您处于一种不太人为的情况,即存在为节点编写的自定义equals和hashCode方法,那么您可能不得不求助于使用hashCode和equals方法通过包装类跟踪节点,这些包装类通过系统#identityHashCode调用和对真实节点的引用相等检查进行代理。否则,算法可能会在循环确实不存在时确定循环存在。您是否尝试过逐步调试代码?当链接列表中没有循环时,您的代码将进入无限循环。我认为最后一个“else if”处理的是链接列表中没有循环的情况,由于它在到达列表末尾时返回false(它不返回contains,而是直接返回false),请详细说明“它在执行时失败”的含义。输入是什么?结果如何?你以为会是什么呢。是的,我试过调试我的代码,看起来还不错。2.我所说的“执行时间失败”是指网站给我的信息是“提交结果:超出时间限制”。输入(这是自动的)是一个很长的链表,而预期的输出,引用网站上的话,“tail连接到节点索引5902”,这意味着链表中有一个循环。非常感谢!!我现在从ArrayList更改为HashSet,不再超过时间限制!非常感谢您的提示,也感谢您耐心地撰写所有这些解释@没问题!我看你是新来的。如果您觉得某个答案解决了您一直遇到的问题,那么单击旁边的绿色复选标记将其标记为“已接受”,这是一种常见的礼貌。它有助于确保人们未回答的问题始终处于聚光灯下,这样每个人都能得到他们需要的帮助。