Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 检测链表中的循环_Java_Linked List_Infinite Loop_Circular Reference - Fatal编程技术网

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是安全的
在任何情况下,都不会有分支导致程序状态以某种方式不前进,因此可以安全地说,拥有无限循环不是问题

您的算法的真正问题看起来是它的时间复杂性。要确保java.util.ArrayList不包含特定值,需要完全遍历该列表并每次在每个元素上调用对象#equals。如果您坚决反对使用一种更传统的循环节点链接检查算法,比如您链接的算法,那么我绝对建议您使用java.util.HashSet来执行类似的操作。通过设计,它可以非常快速地查找元素是否存在于其中


此外,如果您处于一种不太人为的情况,即存在为节点编写的自定义equals和hashCode方法,那么您可能不得不求助于使用hashCode和equals方法通过包装类跟踪节点,这些包装类通过系统#identityHashCode调用和对真实节点的引用相等检查进行代理。否则,算法可能会在循环确实不存在时确定循环存在。

您是否尝试过逐步调试代码?当链接列表中没有循环时,您的代码将进入无限循环。我认为最后一个“else if”处理的是链接列表中没有循环的情况,由于它在到达列表末尾时返回false(它不返回contains,而是直接返回false),请详细说明“它在执行时失败”的含义。输入是什么?结果如何?你以为会是什么呢。是的,我试过调试我的代码,看起来还不错。2.我所说的“执行时间失败”是指网站给我的信息是“提交结果:超出时间限制”。输入(这是自动的)是一个很长的链表,而预期的输出,引用网站上的话,“tail连接到节点索引5902”,这意味着链表中有一个循环。非常感谢!!我现在从ArrayList更改为HashSet,不再超过时间限制!非常感谢您的提示,也感谢您耐心地撰写所有这些解释@没问题!我看你是新来的。如果您觉得某个答案解决了您一直遇到的问题,那么单击旁边的绿色复选标记将其标记为“已接受”,这是一种常见的礼貌。它有助于确保人们未回答的问题始终处于聚光灯下,这样每个人都能得到他们需要的帮助。