簡體   English   中英

訪問 SortedSet 中特定元素的最有效方法是什么?

[英]What is the most efficient way to access particular elements in a SortedSet?

我想使用一個排序的集合,但我可以在其中按索引訪問元素,即我想要具有集合和列表特征的東西。 Java.util.TreeSet 非常接近我的需要,但不允許通過索引進行訪問。

我可以想到幾個選項:

  1. 每次需要特定元素時,我都可以遍歷 TreeSet。
  2. 當我需要訪問特定元素時,我可以維護一個 TreeSet 並從中生成一個 List。
  3. 同上,只緩存 List 直到 Set 改變。
  4. 我可以有一個 List 並在需要添加元素時自己對它進行排序。
  5. 等等。

各種選項之間存在各種權衡。 我希望有人能給我一些好的建議。 要回答有關“您為什么要這樣做?”的潛在問題,請閱讀Apriori算法。

幾點:

  • 有點沒有答案,但是當我最后需要重新實現頻繁項集挖掘算法時,我選擇了 FP-growth,它的性能與先驗不相上下(或更好),而且在我看來,它更容易來實施。 該技術由韓嘉偉等人開發,基本上在數據挖掘:概念和技術中有專門的章節。

  • 有幾種開源工具采用非常標准化的輸入(每行一個整數列表;整數代表項,行代表項集)。 其中一些為您提供算法選擇。 其中許多可在此處獲得許可許可: http : //fimi.ua.ac.be/src/

  • 請記住,除非您專門使用數組/向量,否則僅使用任何List實現都不會讓您獲得O(1)元素訪問權限。 更有可能的是,通過保留大部分或完全排序的數組(使用二分搜索查找超過特定限制的元素,以及隨機訪問的常用索引),您將獲得更好的里程。

https://github.com/geniot/indexed-tree-map

我有同樣的問題。 於是我拿了 java.util.TreeMap 的源碼,寫了IndexedTreeMap 它實現了我自己的IndexedNavigableMap

public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
   K exactKey(int index);
   Entry<K, V> exactEntry(int index);
   int keyIndex(K k);
}

該實現基於在更改時更新紅黑樹中的節點權重。 權重是給定節點下的子節點數加上一個 - self。 例如,當一棵樹向左旋轉時:

    private void rotateLeft(Entry<K, V> p) {
    if (p != null) {
        Entry<K, V> r = p.right;

        int delta = getWeight(r.left) - getWeight(p.right);
        p.right = r.left;
        p.updateWeight(delta);

        if (r.left != null) {
            r.left.parent = p;
        }

        r.parent = p.parent;


        if (p.parent == null) {
            root = r;
        } else if (p.parent.left == p) {
            delta = getWeight(r) - getWeight(p.parent.left);
            p.parent.left = r;
            p.parent.updateWeight(delta);
        } else {
            delta = getWeight(r) - getWeight(p.parent.right);
            p.parent.right = r;
            p.parent.updateWeight(delta);
        }

        delta = getWeight(p) - getWeight(r.left);
        r.left = p;
        r.updateWeight(delta);

        p.parent = r;
    }
  }

updateWeight 只是將權重更新到根:

   void updateWeight(int delta) {
        weight += delta;
        Entry<K, V> p = parent;
        while (p != null) {
            p.weight += delta;
            p = p.parent;
        }
    }

當我們需要按索引查找元素時,這里是使用權重的實現:

public K exactKey(int index) {
    if (index < 0 || index > size() - 1) {
        throw new ArrayIndexOutOfBoundsException();
    }
    return getExactKey(root, index);
}

private K getExactKey(Entry<K, V> e, int index) {
    if (e.left == null && index == 0) {
        return e.key;
    }
    if (e.left == null && e.right == null) {
        return e.key;
    }
    if (e.left != null && e.left.weight > index) {
        return getExactKey(e.left, index);
    }
    if (e.left != null && e.left.weight == index) {
        return e.key;
    }
    return getExactKey(e.right, index - (e.left == null ? 0 : e.left.weight) - 1);
}

查找鍵的索引也非常方便:

    public int keyIndex(K key) {
    if (key == null) {
        throw new NullPointerException();
    }
    Entry<K, V> e = getEntry(key);
    if (e == null) {
        throw new NullPointerException();
    }
    if (e == root) {
        return getWeight(e) - getWeight(e.right) - 1;//index to return
    }
    int index = 0;
    int cmp;
    index += getWeight(e.left);
    
    Entry<K, V> p = e.parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        while (p != null) {
            cmp = cpr.compare(key, p.key);
            if (cmp > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    } else {
        Comparable<? super K> k = (Comparable<? super K>) key;
        while (p != null) {
            if (k.compareTo(p.key) > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    }
    return index;
}

你可以在https://github.com/geniot/indexed-tree-map找到這項工作的結果

也許 Treeset 和 apache 公共集合 API CollectionUtils.get() 的組合可以解決您的問題

我會研究LinkedHashSet 它維護 HashSet 的插入順序。

暫無
暫無

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

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