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

Java 如何使用O(logN)对具有n个元素的优先级队列进行排序?,java,tree,heap,priority-queue,Java,Tree,Heap,Priority Queue,我有一个整数流,还有一个int k,由用户给出。在程序结束时,我必须打印k个最大的数字。我只允许使用容量为k的优先级队列 我的问题是,当队列达到满容量时,下一个整数必须替换队列中最低的整数 如何在插入后保持队列排序,以便知道在下一次迭代中替换哪个int,复杂性为O(logn)?我使用了一个swim方法(如下所示),但是,虽然它将把新的int置于正确的级别,但它并不能使队列完全排序 以下是游泳的方法: private void swim(int i){ while (i > 1) {

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

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

如何在插入后保持队列排序,以便知道在下一次迭代中替换哪个int,复杂性为O(logn)?我使用了一个swim方法(如下所示),但是,虽然它将把新的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;
    }
} 

您可以在二叉树中排列数据,并通过二叉树搜索查找要删除某些内容的时间的最小值。 二叉树搜索的复杂度为O(logn),插入元素的复杂度也为O(logn)

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


您可以查看此链接,了解如何在数组中实现二叉树。

即使您在步骤5、104和69中的注释
也会切换位置
,以便在每次迭代后,最低的元素位于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");
        }
    }
}

首先,您不能将
PriorityQueue
按顺序排序;如果与堆数据结构不完全相同,则与之类似。
PriorityQueue
仅授权顶部元素是最小值或最大值,根据它是最小值或最大值堆

另外,您还将混淆两个不同的问题:排序元素和查找K max/min元素

如果要对给定的N元素列表中的元素进行排序:
使用基于比较的排序算法,没有比O(N*log(N))更好的运行时间了

但是,如果您的案例只是从N元素列表中查找K min/max元素:
您可以在O(N*log(K))时间内实现它


请检查一下这个问题:

你想达到什么目标还不太清楚。如果队列的大小小于
k
则元素按其自然顺序排序(优先级队列的默认行为)。当队列的大小等于
k
时,元素按插入顺序排序,最后一个元素替换为下一个添加的元素?是否应从队列中删除上一个最后元素?@次优。正如您所说,最低的元素应该替换为下一个添加的元素(如果它更大)。问题是,有时更换了错误的元件。在本例中,93将替换69而不是42。在索引A的步骤4之后设置了哪个规则
104
,并交换69和42的顺序?为了与您在第5步中所说的内容保持一致,应该改为69、42、104。@次优对不起,这是一个输入错误。在步骤5,在右下角插入104(不是69),替换32。然后,swim将其切换到顶部的69位。您应该回顾您的示例。现在我们知道了
104
是从哪里来的。但是为什么在步骤5中
69,42
(从步骤4开始)的顺序在步骤5中变成
(42,69)
?为什么在第6步
93
替换
69
,而不是
42
?与您的
下一个整数读取不一致的必须替换队列中最低的
。您对
java.util.PriorityQueue
的约束是什么?队列中的所有k元素都应该按照其自然顺序排序吗?这与堆数据结构完全相同。
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