我当然可以做以下事情:
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();
}
但是这种方法清空了我想保留的队列。我知道我可以使用那个比较器进行排序(当然,当它不像上面那么简单)来获取这个数组,但是我必须首先创建一个数组,然后将元素从队列复制到数组,然后对数组进行排序
有没有更好的方法?谢谢你的帮助!
答案 0 :(得分:5)
来自PriorityQueue
的Javadoc:
这个类及其迭代器实现了所有可选方法
Collection
和Iterator
接口。提供的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);
}