比较循环链接列表等于方法


public class LinkedList {
 Object contents;
 LinkedList next = null;
public boolean equals(Object item) {
   return (this == item) || ((item instanceof LinkedList) &&  this.equals((LinkedList)item)); 
  }
 public boolean equals(LinkedList item) { 
   return myUtil.equals(this.contents, item.contents) && myUtil.equals(this.next, item.next); 
 }
} 
public class myUtil{
  public static boolean equals(Object x, Object y) {
    return (x == y) || (x != null && x.equals(y));
 }
}
main(){
 LinkedList myList = new LinkedList();
 myList.next = new LinkedList();
 LinkedList head = myList.next;
 myList.next = head;
}

我想我在这里创建了一个循环链接列表。所以我所做的是覆盖 equals 方法以确保处理循环引用:

由于某种原因,LinkedList.equals似乎没有返回...是因为我的循环链接列表,还是我错过了一些条件?

此代码的主要问题是您的比较不会在循环引用时终止,并且如果所有内容字段相等,则会永远循环。它将始终持续到下一个比较,并且由于下一个项目始终存在(因为它是一个圆圈),这将永远持续下去。

myUtil.equals(this.contents, item.contents) && myUtil.equals(this.next, item.next);

要解决此问题,最简单的方法是向每个列表项添加一个布尔私有"访问"字段。比较时,在比较后对每个项目设置访问量。如果两者都未访问且相同,请继续。如果只访问了一个,则您的列表不相同。如果两者都被访问,则您已经比较了整个列表的可访问性。通常,在列表中包含循环是一个坏主意,并且存在专门用于检测它们的算法。这可能是一个令人困惑的话题。以下是环路检测的介绍,可帮助您进一步了解问题。请记住,如果您使用访问过的字段,则必须在 equals() 中使用另一个循环取消设置所有这些字段,以允许它再次运行。

另一方面,您不会初始化测试列表节点的内容字段。这在这里没关系,因为它们被初始化为 null,但通常最好显式初始化所有字段。

一般来说,您也不需要equals(Object item)覆盖。尝试

public boolean equals(LinkedList item){
  if (this == item){
     return true; // It's the same object
  }
  // Add some null checks here, I'm lazy
  if (this.visited && item.visited && this.contents.equals(item.contents){
     this.visited = false; //Unset
     item.visited = false;
     return true;
  }
  if (this.visited && !item.visited){
      this.visited = false;
      return false;
  }
  if (!this.visited && item.visited){
      item.visited = false;
      return false;
  }
  if (!this.visited && !item.visited && this.visited.contents.equals(item.contents){
      this.visited = true;
      item.visited = true;
      boolean ret = this.next.equals(item.next);
      this.visited = false;
      item.visited = false;
      return ret;
  }
  // Contents not equal
  return false;
}

这回溯和取消设置了一些基本的递归。我显然没有编译这个,但这就是它的要点,我想(我希望没有太多错误)

两个问题,首先你没有循环链表。下面的代码创建 2 个列表,list1.next = list2,list2.next = null。未创建圆圈。

LinkedList myList = new LinkedList();
myList.next = new LinkedList();
LinkedList head = myList.next;
myList.next = head;

其次,如果你确实有一个循环链表,下面的将产生一个无限循环,因为没有达到结束条件,这是因为在循环链接链接中,next永远不应该null

public boolean equals(Object item) {
  return (this == item) || ((item instanceof LinkedList) &&       
    this.equals((LinkedList)item)); 
}
public boolean equals(LinkedList item) { 
   return myUtil.equals(this.contents, item.contents) && myUtil.equals(this.next, item.next); 
}

为了有效地做到这一点,你需要提供一些机制来以非循环的方式迭代列表,即使这个机制是私有的,不向其他用户公开。一种方法是将单个节点标记为"根"。

return myUtil.equals(this.contents, item.contents) 
&& myUtil.equals(this.next, item.next); 

我想这是你的问题,正如你所怀疑的那样,当你执行 && 的第二个表达式时,myUtil.equals(this.next, item.next);你输入执行这一行的 myUtil.equals 方法:

return (x == y) || (x != null && x.equals(y));

它反过来使用x的.equals()方法,该方法将对其item.next重复该过程,依此类推,因为你有一个循环链表。

这将导致无限循环,这是因为在代码中:

public static boolean equals(Object x, Object y) {
        return (x == y) || (x != null && x.equals(y));
    }

x.equals(y)将再次调用:

public boolean equals(LinkedList item) {
        return myUtil.equals(this.contents, item.contents)
                && myUtil.equals(this.next, item.next);
    }

但是如果你正在执行myList1.equals(myList1),你不会得到无限循环,因为myUtils.equals()中的(x==y)会返回true所以如果你比较相同的对象,无限循环不会发生。

但是,当您比较不同的对象时,您将进入无限循环。

这不是循环列表问题,这是因为您选择的代码设计。

终于完成了我的 equals 方法实现。为此,我不得不自己使用其他检查工具。我不能说它是否有效,但检查了一些特殊状态。

public boolean equals(Object o)
{
    if(!(o instanceof CircularlyLinkedList))
        return false;
    CircularlyLinkedList<E> list=(CircularlyLinkedList<E>)o;
    if(this==list)
        return true;
    if(size()!=list.size())
        return false;
    //tail element of this object
    Node<E> thisTail=tail;
    //tail element of list passing as parameter
    Node<E> listTail=list.tail;
    //checking if tail elements of both lists are the same or not. If not rotate list till equatation is provided for tails
    if(!thisTail.equals(listTail))
    {
        listTail = equate(list);
        if(listTail==null)
            return false;
    }
    //Each element checking
    for(int i=0; i<size(); i++)
    {
        thisTail=thisTail.next;
        listTail=listTail.next;
        if(!thisTail.equals(listTail))
        {
            listTail = equate(list);
            listTail=tail;
            i=0;
            if(listTail==null)
                return false;
        }
    }
    return true;
}

等同方法:

private Node<E> equate(CircularlyLinkedList<E> list)
{
    Node<E> thisTail=tail;
    Node<E> listTail;
    for(int i=0; i<list.size(); i++)
    {
        list.rotate();
        listTail=list.tail;
        //If full rotation completes then returns null
        if(list.getRotation()==0)
        {
            return null;
        }
        if(thisTail.equals(listTail))
        {
            return nodeList;
        }
    }
    return null;
}

getRotate 方法返回旋转操作的计数以及介于 0 和大小 1 之间的变化。我希望它将变得有用。

相关内容

  • 没有找到相关文章

最新更新