列出维护排序的实现

时间:2012-05-20 17:07:53

标签: java list collections insertion-order

Java中是否存在基于提供的List维护订单的Comparator实现?

可以通过以下方式使用的东西:

Comparator<T> cmp = new MyComparator<T>();
List<T> l = new OrderedList<T>(cmp);
l.add(someT);

以便插入someT,以便根据cmp

维护列表中的顺序

(关于@andersoj的建议我正在用另外一个请求完成我的问题)

此外,我希望能够按排序顺序遍历列表而不删除元素,即:

T min = Const.SMALLEST_T;
for (T e: l) {
  assertTrue(cmp.compare(min, e) >= 0);
  min = e;
}

应该通过。

欢迎所有建议(除了告诉我在无序完整列表中使用Collections.sort),但是,我更喜欢java.*或最终org.apache.*中的某些内容,因为它很难现在介绍新的图书馆。

注意:(更新4) 我意识到这种列表的实现性能不佳。有两种一般方法:

  1. 使用链接结构(某种)B树或类似的
  2. 使用数组和插入(使用二进制搜索)
  3. 否1. CPU缓存未命中有问题 没有2.在数组中移位元素有问题。

    UPDATE2: TreeSet不起作用,因为它使用提供的比较器(MyComparator)来检查是否相等,并基于它假设元素相等并排除它们。我需要那个比较器只用于排序,而不是“唯一性”过滤(因为元素按其自然顺序不相等)

    UPDATE3: PriorityQueue不能用作List(因为我需要),因为没有办法按照“排序”的顺序遍历它,要按照排序顺序获取元素,你必须从中删除它们集合。

    更新:

    类似的问题:
    A good Sorted List for Java
    Sorted array list in Java

3 个答案:

答案 0 :(得分:17)

您应该使用TreeSet

  

元素按照其自然顺序排序,或者在创建时创建时提供的比较器,具体取决于使用的构造函数。

示例:

Comparator<T> cmp = new MyComparator<T>();
TreeSet<T> t = new TreeSet<T>(cmp);
l.add(someT);

请注意,这是设置,因此不允许重复的条目。这可能适用于您的特定用例,也可能不适用。

答案 1 :(得分:9)

对新要求的回应。我看到两个潜力:

  • 执行PriorityQueue的JavaDoc所说的内容:

      

    此类及其迭代器实现Collection和Iterator接口的所有可选方法。方法iterator()中提供的迭代器不保证以任何特定顺序遍历优先级队列的元素。如果您需要有序遍历,请考虑使用Arrays.sort(pq.toArray())

    我怀疑根据您的要求,这将产生最佳性能。如果这是不可接受的,您需要更好地解释您要完成的工作。

  • 构建列表,只需添加新元素即可自行排序。这是一个真正的痛苦...如果您使用链接结构,您可以进行有效的插入排序,但局部性很差。如果您使用了数组支持的结构,插入排序很痛苦,但遍历更好。如果迭代/遍历不频繁,您可以保持列表内容未排序并仅按需排序。

  • 按照我的建议考虑使用 PriorityQueue ,如果需要按顺序迭代,请编写一个包装器迭代器:

    class PqIter implements Iterator<T>
    {
       final PriorityQueue<T> pq;
       public PqIter(PriorityQueue <T> source)
       {
         pq = new PriorityQueue(source); 
       }
    
       @Override
       public boolean hasNext()
       {
         return pq.peek() != null
       }
    
       @Override
       public T next()
       { return pq.poll(); }
    
       @Override
       public void remove()
       { throw new UnsupportedOperationException(""); }
    }
    
  • 使用Guava的TreeMultiSet。我使用Integer测试了以下代码,它似乎做了正确的事。

    import com.google.common.collect.TreeMultiset;
    
    public class TreeMultiSetTest { 
      public static void main(String[] args) {
        TreeMultiset<Integer> ts = TreeMultiset.create();
        ts.add(1);  ts.add(0); ts.add(2);
        ts.add(-1); ts.add(5); ts.add(2);
    
        for (Integer i : ts) {
          System.out.println(i);
        } 
      } 
    }
    

以下介绍了使用SortedSet时遇到的唯一性/过滤问题。我看到你也想要一个迭代器,所以这不会起作用。

如果你真正想要的是一个有序的列表的东西,你可以使用PriorityQueue

Comparator<T> cmp = new MyComparator<T>();
PriorityQueue<T> pq = new PriorityQueue<T>(cmp);
pq.add(someT);

请注意API文档中有关各种操作的时间属性的内容:

  

实施说明:此实施为入队和出列方法提供了 O(log(n))时间(offerpollremove()和{ {1}}); addremove(Object)方法的线性时间;和常量时间用于检索方法(contains(Object)peekelement)。

您还应该知道size生成的迭代器的行为并不像预期的那样:

  

方法PriorityQueue中提供的Iterator无法保证以任何特定顺序遍历优先级队列的元素。如果您需要有序遍历,请考虑使用iterator()

我刚注意到Guava提供了MinMaxPriorityQueue。此实现是由阵列支持的,而不是JDK的Arrays.sort(pq.toArray())中提供的链接表单,因此可能具有不同的计时行为。如果您正在做一些对性能敏感的事情,您可能希望看一看。虽然音符给出了略微不同(线性和对数)的大O次,但所有这些时间也应该是有界的,这可能是有用的。

本身没有PriorityQueue实现维护排序,但您可能正在寻找的是SortedSet的实现。 TreeSet是最常见的。另一个实现,List用于更具体的用途。请注意,ConcurrentSkipListSet提供排序,但不允许重复输入,SortedSet也是如此。

参考文献:

答案 2 :(得分:-1)

我有类似的问题,我正在考虑使用TreeSet。为了避免排除“相等”元素,我将修改比较器,而不是返回0,它将在(-1,1)之间返回一个随机数,否则它将始终返回1.

如果您无法控制比较器,或者您正在使用它而不是插入此解决方案,则不适合您。