簡體   English   中英

比較循環鏈表等於方法

[英]Comparing circular linkedlists equals method

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;

其次,如果您 DID 有一個循環鏈接列表,以下將產生無限循環,因為沒有達到結束條件,這是因為在循環鏈接鏈接中, 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(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) myUtils.equals()將返回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;
}

getRotation方法返回旋轉操作的計數並在 0 和size-1之間變化。 我希望它會變得有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM