如何用O(logN)对具有n个元素的优先级队列进行排序?

时间:2015-12-17 09:30:30

标签: java tree heap priority-queue

我有一个整数流,以及一个由用户给出的int k。在程序结束时,我必须打印k个最高数字。我只允许使用容量为k的优先级队列。

我的问题是当队列达到满容量时,下一个整数读取必须替换队列中的最低值。

如何在插入后对队列进行排序,以便我知道在下一次迭代中要替换哪个int,具有O(logn)复杂度?我使用了一个游泳方法(如下所示),但是,虽然它会将新的int放在正确的级别,但它并不会使队列完全排序。

这是游泳方法:

private void swim(int i){
    while (i > 1) {  //if i root (i==1) return
        int p = i/2;  //find parent
        int result = cmp.compare(heap[i], heap[p]);  //compare parent with child
        if (result == 1) return;    //if child <= parent return
        swap(i, p);                 //else swap and i=p
        i = p;
    }
} 

为了让自己更清楚,这里有一个k = 3的例子。

Example

1: A = 42 / B = null / C = null

 2: A = 69 / B= 42 / C = null (69 swims upwards)

3: A = 69 / B= 42 / C = 32

 4: A = 69 / B= 42 / C = 32 (no change)

 5: A = 104 / B= 42 / C = 69 (104 is inserted replacing 32, then swims upwards)

 6: A = 104 / B= 42 / C = 93 (93 is inserted replacing 69, remains there)       

3 个答案:

答案 0 :(得分:1)

首先,您不能将PriorityQueue保持在排序顺序;它与堆数据结构类似,如果不完全相同。而且你在排序和找到K max / min元素之间也感到困惑。如果要对给定列表中的所有元素进行排序,则使用基于比较的排序可以获得比 O(NlogN)更好的运行时间。但是,如果您的案例只是从 N 元素列表中找到 K min / max元素,那么您可以在 O(NlogK)时间。请检查一次此问题:Finding the first n largest elements in an array

答案 1 :(得分:0)

即使您的评论In step 5, 104 and 69 switch placesso that after each iteration, the lowest element is at C也不一致。因为在第5步中,最低值42位于B

也许您正在寻找与此类似的解决方案。

public class FixedCapacityPriorityQueue {

    static class MyPriorityQueue extends PriorityQueue<Integer> {

        private final int capacity;

        public MyPriorityQueue(int capacity) {
            super(capacity, Comparator.reverseOrder());
            this.capacity = capacity;
        }

        @Override
        public boolean add(Integer i) {
            super.add(i);
            if (size() > capacity) {
                Integer lowest = Integer.MAX_VALUE;
                for (Integer next : this) {
                    if (lowest.compareTo(next) > 0) {
                        lowest = next;
                    }
                }
                this.remove(lowest);
            }
            return true;
        }
    }

    public static void main(String[] args) {
        Integer[] stream = {42, 69, 32, 5, 104, 93};

        for (int i = 0; i < stream.length; i++) {
            PriorityQueue queue = new MyPriorityQueue(3);
            System.out.print("added to queue   : ");
            for (int e = 0; e <= i; e++) {
                 System.out.printf("%d ", stream[e]);
                queue.add(stream[e]);
            }
             System.out.println();
            System.out.print("elements in queue: ");
            while (queue.size() > 0) {
                System.out.printf("%d ", queue.poll());
            }
            System.out.printf("%n%n");
        }
    }
}

输出

added to queue   : 42 
elements in queue: 42 

added to queue   : 42 69 
elements in queue: 69 42 

added to queue   : 42 69 32 
elements in queue: 69 42 32 

added to queue   : 42 69 32 5 
elements in queue: 69 42 32 

added to queue   : 42 69 32 5 104 
elements in queue: 104 69 42 

added to queue   : 42 69 32 5 104 93 
elements in queue: 104 93 69 

答案 2 :(得分:-1)

您可以在二叉树中安排数据,并使用二叉​​树搜索找到您希望删除某些内容的最小数字。 二叉树搜索的复杂性是O(log N),并且元素的插入也具有O(log N)复杂度。

现在谈论你对长度为k的队列的约束,你可以转换二叉树并将其存储在长度为k的数组中。

您可以查看此链接If I store a binary tree in an array, how do I avoid the wasted space?,了解如何在数组中实现二叉树。