2017-06-14 80 views
2

假設我有此類:在TreeSet中交換密鑰?

public class Node implements Comparable<Node>{ 
    public float key; 
    public TreeSet<Node> neighbors; 

    public Node{ 
    //fill neighbors somehow 
    } 

    @Override 
    public int compareTo(Node n) { 
    if(this.key == n.key) 
     return 0; 
    else if(this.key > n.key) 
     return 1; 
    else 
     return -1; 
    } 

} 

所以這是一個曲線圖,其中每個節點被連接到一組節點(即它的鄰居)的一個典型的節點。我使用的是TreeSet,因爲我經常(經常)以比他們的關鍵字大(小)的關鍵字來知道所有的鄰居。現在,讓我們假設我有這樣的方法:

//swap nodes keys 
void swapKeys(Node a, Node b){ 
    float ak = a.key; 
    a.key = b.key; 
    b.key = ak; 
} 

注意,此方法只改變了兩個節點的密鑰,僅此而已。

做這個「打破」的結構,或一切將繼續正常工作?

如果破壞了結構,你看這個簡單的解決方案:

//swap nodes keys 
void swapKeys(Node a, Node b){ 
    a.remove(b); 
    b.remove(a); 
    float ak = a.key; 
    a.key = b.key; 
    b.key = ak; 
    a.add(b); 
    b.add(a); 
} 
+0

這將打破結構。密鑰應該是不可變的。一旦添加爲密鑰,哈希碼不能更改。 –

+0

@PiotrGwiazda感謝您的回答。我剛剛發佈的解決方案呢? – justHelloWorld

+0

@JonnyHenly當你發佈你的評論時編輯lol – justHelloWorld

回答

1

TreeSet文檔:

注意,排序由一組維護(無論是否明確 比較提供)必須與 正確實現Set接口時的等於一致。

NodeComparable執行不與equals一致。 (compareTo可以返回0兩個Node實例不相等)。

這本身使您的Node類不適合作爲TreeSet的元素。

即使建議的解決方法也是不夠的。

您可能會試圖通過執行equals()(和hashCode())以基於節點中包含的值來解決此問題。但無濟於事,因爲這將違背一個警告,對一般Set接口的機制的文檔:

注:必須要非常謹慎,如果使用可變對象作爲設定 元素行使。如果以影響等於比較的方式更改對象的值,則不指定對象的行爲,而對象是集合中的元素的對象的組合。這種 禁止的一個特例是不允許一個集合將其本身作爲一個元素包含在其中 。

因此,添加equals和hashCode仍然不夠:您的實例也必須是不可變的。

但是最簡單的辦法,似乎是完全放棄了Comparable接口,不實現equalshashCode,並簡單地用一個HashSet代替TreeSet的。在這種情況下,您可以更改節點的內容,而不會影響鄰居組的正常運行。

+0

感謝您的評論。你是否告訴我,我也必須實現'equals'? – justHelloWorld

+0

不,請參閱編輯答案。 – bowmore

+0

不幸的是'HashSet'不是一個選項,因爲我經常使用'tailSet'和'headSet'來計算topk,如[這裏]解釋的那樣(https://stackoverflow.com/questions/44525091/how-to-get-the-top -k-nearest-elements-in-a-java-treeset) – justHelloWorld