2012-08-16 42 views
1

尋找一個插入順序集合,它還允許有效查詢和位置的子集視圖(如子列表)。似乎最簡單的選擇是採用List的鏈表方式,將節點嵌入爲映射值,並在類上暴露部分或全部列表接口。Java ListSet的某處?

有人會向甲骨文傳遞這個消息嗎?爲已排序的地圖和集合添加了NavigableMap/Set,並且沒有更常見的廣告插入順序等效...

編輯:請不要建議LinkedHashSet - 它沒有任何方法來查詢位置或執行一個相對子集。

+2

爲什麼不實現它自己...和/或發現這不一定是一個簡單的數據結構來實現。 (您列出的約束使得支持查詢位置的時間比O(n)時間更加困難......您可以使用圍繞LinkedHashSet的封裝來構建這些約束。)無論如何,如果您描述了爲什麼您如果想要這種結構,一些圖書館可能真的有興趣將其添加到他們的API中。 – 2012-08-17 00:39:58

+0

原因很簡單:花費大部分時間迭代並查詢其元素部分成員的集合需要隨機訪問,最好是索引。因此無論是地圖還是集合。微笑是'它的一部分'。哪裏列表有一個很好的單一方法(子列表,我認爲這是集合框架中最有啓發性的方法),只有*一些* maps /集合允許它在jdk上,並且只有通過實現噩夢般的Navigable/Set/Map, (僅適用於已排序的集合) - 如果可以爲任何鏈接變體創建子集/映射(索引,索引),請添加getIndex – i30817 2012-08-17 00:54:54

+0

或者,如果getindex太昂貴(需要在某些實現上對節點保留int)直接使用該對象作爲鍵(對於集合實現爲映射),並使用鏈表子結構創建一個「子集」。 linkedhashset.subSet(V low,V high)。雖然 – i30817 2012-08-17 00:59:48

回答

2

你的意思是像java.util.LinkedHashSet

哈希表和Set接口的鏈接列表實現,具有 預知的迭代順序。此實現與HashSet 的不同之處在於它保持一個雙向鏈接列表,其中包含所有 條目。此鏈接列表定義了迭代排序,即將元素插入到集合(插入順序)中的順序。 請注意,如果將元素重新插入集合 ,則插入順序不受影響。 (如果s.add的e元素重新插入到一組S(E)是 調用時s.contains(E)將在 調用之前立即返回true。)

+0

不,我不是特別喜歡linkedhashset,因爲linkedhashset沒有公共接口(或者因爲它擴展了hashset而是私有的)來查詢對象的位置,或者根據那些'before'或'after'對象創建一個子集。 – i30817 2012-08-16 23:38:02

+1

@ i30817所以,你的意思是基本上是一個鏈接的哈希集合與一些額外的操作?這是一個ASF許可證實現:http://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/classlib/modules/luni/src/main/java/java/util/LinkedHashSet.java隨意加強它。 – Marcin 2012-08-17 01:43:28

0

EDIT2:新的最終版本 這裏只是爲了套略有調整功能的版本(一分爲二,不再接受空爲「地圖的開始」),可能有更少的錯誤

public class LinkedSet<E> implements Set<E> { 

private LinkedHashMap<E, Integer> m = new LinkedHashMap<E, Integer>(); 
private int monoticallyIncreasing; 

/** 
* Returns true if the value target was added before (exclusive) 
* limitElem in insertion order. 
* 
* If target or limit are not present on the set this method returns false 
* 
* @param limitElem a E that may be a element of the set or not. 
* @return if target was added before limit (can be reset by removing and 
* re-adding the target, that changes iteration order). 
*/ 
public boolean containsBefore(E target, E limitElem) { 
    if (isEmpty()) { 
     return false; 
    } 

    Integer targetN = m.get(target); 
    if (targetN == null) { 
     return false; 
    } 

    Integer highN = m.get(limitElem); 
    if (highN == null) { 
     return false; 
    } 
    return targetN < highN; 
} 

/** 
* Returns true if the value target was added after (exclusive) 
* previousElem in insertion order. 
* 
* If target or previous are not present on the set this method returns false 
* 
* @param previousElem a E that may be a element of the set or not. 
* @return if target was added before previous (can be reset by removing and 
* re-adding the target, that changes iteration order). 
*/ 
public boolean containsAfter(E target, E previousElem) { 
    if (isEmpty()) { 
     return false; 
    } 

    Integer targetN = m.get(target); 
    if (targetN == null) { 
     return false; 
    } 

    Integer low = m.get(previousElem); 
    if (low == null) { 
     return false; 
    } 
    return low < targetN; 
} 

@Override 
public boolean add(E e) { 
    Integer pos = m.get(e); 
    if (pos == null) { 
     m.put(e, monoticallyIncreasing++); 
     return true; 
    } 
    return false; 
} 

@Override 
public int size() { 
    return m.size(); 
} 

@Override 
public boolean isEmpty() { 
    return m.isEmpty(); 
} 

@Override 
public boolean contains(Object o) { 
    return m.containsKey(o); 
} 

@Override 
public Object[] toArray() { 
    Object[] result = new Object[size()]; 
    int i = 0; 
    for (E e : this) { 
     result[i++] = e; 
    } 
    return result; 
} 

@Override 
@SuppressWarnings("unchecked") 
public <T> T[] toArray(T[] a) { 
    int size = size(); 
    if (a.length < size) { 
     a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); 
    } 
    int i = 0; 
    Object[] result = a; 
    for (E e : this) { 
     result[i++] = e; 
    } 
    if (a.length > size) { 
     //peculiar toArray contract where it doesn't care about the rest 
     a[size] = null; 
    } 
    return a; 
} 

@Override 
public boolean remove(Object o) { 
    return m.remove(o) != null; 
} 

@Override 
public boolean addAll(Collection<? extends E> c) { 
    boolean changed = false; 
    for (E e : c) { 
     changed |= add(e); 
    } 
    return changed; 
} 

@Override 
public boolean containsAll(Collection<?> c) { 
    return m.keySet().containsAll(c); 
} 

@Override 
public boolean retainAll(Collection<?> c) { 
    return m.keySet().retainAll(c); 
} 

@Override 
public boolean removeAll(Collection<?> c) { 
    return m.keySet().removeAll(c); 
} 

@Override 
public void clear() { 
    m.clear(); 
} 

@Override 
public Iterator<E> iterator() { 
    return m.keySet().iterator(); 
} 
} 
+0

humm - 雖然它很有用,但我也想從()/ descendingFrom()那裏得到迭代器。但LinkedHashMap無法訪問其節點列表或節點。猜測它回到了舊版本。 – i30817 2012-08-18 10:52:29

+0

在此[註釋](http://stackoverflow.com/a/12023209/214260)上顯示了一個實現 – i30817 2012-08-19 00:13:14