Java 访问SortedSet中特定元素的最有效方式是什么?

Java 访问SortedSet中特定元素的最有效方式是什么?,java,list,performance,set,Java,List,Performance,Set,我想使用一个已排序的集合,但我可以通过索引访问其中的元素,也就是说,我想要同时具有集合和列表特征的集合。Java.util.TreeSet非常接近我的需要,但不允许通过索引进行访问 我可以想出几个选择: 每当我需要一个特定的元素时,我都可以遍历树集 当我需要访问特定元素时,我可以维护一个树集并从中生成一个列表 如上所述,仅缓存列表,直到集合发生更改 我可以有一个列表,并在需要添加元素时自行排序 等等 在各种选择之间有各种权衡。我希望有人能给我一些好的建议。要回答关于“为什么要这样做?”的潜在问题

我想使用一个已排序的集合,但我可以通过索引访问其中的元素,也就是说,我想要同时具有集合和列表特征的集合。Java.util.TreeSet非常接近我的需要,但不允许通过索引进行访问

我可以想出几个选择:

  • 每当我需要一个特定的元素时,我都可以遍历树集
  • 当我需要访问特定元素时,我可以维护一个树集并从中生成一个列表
  • 如上所述,仅缓存列表,直到集合发生更改
  • 我可以有一个列表,并在需要添加元素时自行排序
  • 等等

  • 在各种选择之间有各种权衡。我希望有人能给我一些好的建议。要回答关于“为什么要这样做?”的潜在问题,请阅读算法。

    也许Treeset和apache commons collections API的组合可以解决您的问题

    以下几点:

    • 这算不上答案,但当我上次需要重新实现一个频繁项集挖掘算法时,我选择了FP-growth,它的性能与先验算法相当(或更好),在我看来,更容易实现。这项技术是由Jiawei Han和其他人开发的,基本上在数据挖掘中有一个专门的章节:概念和技术

    • 有几种开源工具采用相当标准化的输入(每行一个整数列表;整数表示项,行表示项集)。它们中的一些让你可以选择算法。这里提供了许多许可证:

    • 请记住,仅使用任何
      列表
      实现并不能获得
      O(1)
      元素访问,除非您专门使用数组/向量。更有可能的是,您将从保留大部分或完全排序的数组中获得更好的收益(使用二进制搜索查找超过特定限制的元素,并使用常规索引进行随机访问)

      • 我会调查。它维护哈希集的插入顺序。

        我也有同样的问题。因此,我获取了java.util.TreeMap的源代码并编写了IndexedTreeMap。它实现了我自己的索引导航地图

        public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
           K exactKey(int index);
           Entry<K, V> exactEntry(int index);
           int keyIndex(K k);
        }
        
        public interface IndexedNavigableMap扩展了NavigableMap{
        K精确键(int索引);
        条目精确条目(int索引);
        int键索引(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;
            }
          }
        
        private void rotateLeft(条目p){
        如果(p!=null){
        条目r=右侧;
        int delta=getWeight(左)-getWeight(右);
        p、 右=右=左;
        p、 更新视图(增量);
        如果(右左!=null){
        r、 left.parent=p;
        }
        r、 父母=父母;
        如果(p.parent==null){
        根=r;
        }else if(p.parent.left==p){
        delta=getWeight(r)-getWeight(p.parent.left);
        p、 parent.left=r;
        p、 parent.updatewight(delta);
        }否则{
        delta=getWeight(r)-getWeight(p.parent.right);
        p、 parent.right=r;
        p、 parent.updatewight(delta);
        }
        delta=重量(p)-重量(r.左);
        r、 左=p;
        r、 更新视图(增量);
        p、 父代=r;
        }
        }
        
        UpdateView只更新根目录下的权重:

           void updateWeight(int delta) {
                weight += delta;
                Entry<K, V> p = parent;
                while (p != null) {
                    p.weight += delta;
                    p = p.parent;
                }
            }
        
        void updatewight(int delta){
        重量+=增量;
        条目p=父项;
        while(p!=null){
        p、 重量+=增量;
        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 K exactKey(int索引){
        如果(索引<0 | |索引>大小()-1){
        将新的ArrayIndexOutOfBoundsException()抛出;
        }
        返回getExactKey(根,索引);
        }
        私有K getExactKey(条目e,int索引){
        if(e.left==null&&index==0){
        返回e.key;
        }
        if(e.left==null&&e.right==null){
        返回e.key;
        }
        if(e.left!=null&&e.left.weight>index){
        返回getExactKey(如左,索引);
        }
        if(e.left!=null&&e.left.weight==index){
        返回e.key;
        }
        返回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;
        }
        
        public int-keyIndex(K键){
        if(key==null){
        抛出新的NullPointerException();
        }
        条目e=获取条目(键);
        如果(e==null){
        抛出新的NullPointerException();
        }
        if(e==根){
        return getWeight(e)-getWeight(e.right)-1;//要返回的索引
        }
        int指数=0;
        int-cmp;
        索引+=获取权重(如左);
        条目p=e.parent;
        //拆分比较器和可比较路径
        
        Comparator可能会让您对算法和实现指针感兴趣这与我的需求不太相符。Apriori看起来相对简单,可能对我的任务来说效率足够高。我对FP增长不太熟悉。我来看看。谢谢!(+1)KC2001:不客气。“更容易实施”可能是相当主观的,它们可能是标准的。FP增长更有趣一些,而且肯定更接近最先进的。