从Java中的priorityQueue创建有序数组的更好方法

时间:2011-12-27 21:08:23

标签: java

我当然可以做以下事情:

        PriorityQueue<Integer> q = new PriorityQueue<Integer>(100, new Comparator<Integer>() {
            public int compare(Integer x, Integer y) {
                return Integer.valueOf(x).compareTo(y);
            }
        });
        ...//add some elements to q
        int[] arr = new int[q.size()];
        int i = 0;
        while (q.size() != 0) {
            arr[i++] = q.remove();
        }

但是这种方法清空了我想保留的队列。我知道我可以使用那个比较器进行排序(当然,当它不像上面那么简单)来获取这个数组,但是我必须首先创建一个数组,然后将元素从队列复制到数组,然后对数组进行排序

有没有更好的方法?谢谢你的帮助!

7 个答案:

答案 0 :(得分:5)

来自PriorityQueue的Javadoc:

  

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

创建数组,然后对其进行排序。这是规定的方式。

答案 1 :(得分:3)

你不能只清空原始队列的副本吗?

PriorityQueue<Integer> temp = new PriorityQueue<Integer>( q );
int[] arr = new int[ q.size() ];

int i = 0;
while ( !temp.isEmpty() ) {
    arr[ i ] = temp.remove().intValue();
    i++;
}

就像你一样,但是在一个新队列上。我认为复制优先级队列的成本是O(n)。或者它至少应该。清空队列为O(n log n),因此最终成本为O(n log n),就像获取数组然后对其进行排序一样。

答案 2 :(得分:1)

由于Queue扩展了Collection,你应该能够迭代它。

for(Integer iq:queue)   arr [i ++] = iq;

嗯,如果@amit是正确的,PriorityQueue doest保证按顺序迭代,这不会工作。

另一个编辑跟随......

我们中的许多人都了解到PriorityQueue不会按顺序迭代。这是因为PriorityQueue只对元素​​进行了部分排序,它主要跟踪头元素(最少)。

保留原始PriorityQueue的一个建议是制作副本,并从副本中取出/排出。另一种是从内容中创建一个List(因为你知道确切的大小,我认为ArrayList是最合适的)并且明确地对List进行排序。

我的猜测是List会更快。我们知道它是O(n log(n))。现在,PriorityQueue javadocs说添加和删除是O(log(n))。而且你会调用它们N次,所以理论上,PriorityQueue也是O(n log(n))。

但是,如果使用PriorityQueue实际上比这个常见用例的排序更快,迭代有序列表,我想我会看到许多“性能提示”文章说“使用PriorityQueue而不是Collections.sort”( )“。我还没有。我错过了吗?

无论如何,OP可以尝试两者并报告。对我来说,如果PriorityQueue比排序List更快,那将是一个引人入胜且有用的发现。

我对100万个随机整数进行了一些测试。排序的ArrayList比我在古老的7岁桌面JDK6上从PriorityQueue排出的速度大约快2倍。代码如下。

public class StackOverflow2 {

   ArrayList<Integer> generateRandomList(int count, int seed) {
      ArrayList<Integer> list = new ArrayList<Integer>(count);
      Random random = new Random();
      random.setSeed(seed);
      for (int i=0; i<count; i++)
         list.add(Integer.valueOf(random.nextInt()));

      return list;
   }

   long usePriorityQueue(ArrayList<Integer> inList) {
      long total = 0;
      long start = System.currentTimeMillis();

      PriorityQueue<Integer> pq = new PriorityQueue<Integer>(inList);
      while (!pq.isEmpty()) {
         total += pq.remove();  // do something so HotSpot doesn't optimize this away...
      }

      long totaltime = System.currentTimeMillis() - start;
      System.out.println("usePriorityQueue  totaltime = " + totaltime);
      return total;
   }

   long useArrayList(ArrayList<Integer> inList) {
      long total = 0;
      long start = System.currentTimeMillis();

      ArrayList<Integer> list = new ArrayList<Integer>(inList);
      Collections.sort(list);
      for (Integer iii : list) {
         total += iii;  // do something
      }

      long totaltime = System.currentTimeMillis() - start;
      System.out.println("useArrayList  totaltime = " + totaltime);
      return total;
   }

   public static void main(String[] args) {
      StackOverflow2 so2 = new StackOverflow2();
      ArrayList<Integer> randoms = so2.generateRandomList(1000000, 123456);

      for (int i=0; i<10; i++) {
         long upq = so2.usePriorityQueue(randoms);
         long ual = so2.useArrayList(randoms);
      }

   }
}

答案 3 :(得分:0)

使用LinkedList作为中间集合。它的构造函数按照提供的集合指定的顺序添加元素,并且其toArray(T[] arr)方法保留了列表排序。

PriorityQueue<Integer> q = new PriorityQueue<Integer>(100, new Comparator<Integer>() {
    public int compare(Integer x, Integer y) {
        return Integer.valueOf(x).compareTo(y);
    }
});

/* ...elided, add items... */

List<Integer> integers = new LinkedList<Integer>(q);
Integer[] orderedIntegerArray = integers.toArray(new Integer[0]);

答案 4 :(得分:0)

您可以使用迭代器循环迭代队列。

for (Iterator<Integer> iterator = q.iterator(); iterator.hasNext();) {
    arr[i++] = iterator.next();
}

答案 5 :(得分:0)

如果您想要短信代码,可以随时使用toArray()sort

Integer[] arr = q.toArray(new Integer[1]);
Arrays.sort(arr,q.comparator());

编辑:如果您不使用自然顺序,则需要将相同的比较器发送到sort()[修复代码示例中的第二行]

答案 6 :(得分:0)

您可以使用ArrayList,然后使用二进制搜索来查找项目的放置位置。因此,插入是有序的

private List<Integer> items = new ArrayList<Integer>();            

while (q.size() != 0) {
    int index = Collections.binarySearch(items, q.remove());
    if (index >= 0) {
        index++;
    } else {
        index = -(index + 1);
    }
    items.add(index, q.remove);
}