简体   繁体   中英

How to sort with O(logN) a priority queue with n-elements?

I have a stream of integers, as well as an int k, given by the user. At the end of the program I must print the k highest numbers. I am only allowed to use a priority queue with a capacity of k.

My problem is that when the queue reaches full capacity, the next integer read must replace the lowest in the queue.

How can I keep the queue sorted after insertion, so that I know which int to replace in the next iteration, with O(logn) complexity? I use a swim method (presented bellow), but ,while it will place the new int at the right level, it doesn't keep the queue entirely sorted.

Here's the swim method:

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;
    }
} 

To make myself more clear here's an example for k = 3.

例

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)       

First of all, you can't keep the PriorityQueue in sorted order; it is similar, if not exactly same as a heap data structure.
PriorityQueue just grantee the top element is the min OR max according to it is min OR max heap.

And also you are getting confused between 2 different problems Sorting elements and Finding K max/min elements .

If you want to Sort elements in a given list of N elements:
You can't get a better running time than O(N*log(N)) using a comparison based sort algorithm.

But, if your case is just Finding K min/max elements from a list of N elements:
You can achieve it in O(N*log(K)) time.

Please check this question once: Finding the first n largest elements in an array

Even your comments In step 5, 104 and 69 switch places and so that after each iteration, the lowest element is at C are not consistent. Because in step 5 the lowest value 42 is at B .

Maybe you are looking for a solution similar to this one.

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");
        }
    }
}

output

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 

You can arrange you data in binary tree and with a binary tree search find the min number its time you want to delete something. The complexity for binary tree search is O(log N) and the insert of an element it has also O(log N) complexity.

Now talking about your constraint on the queue with length k you can transform the binary tree and store it in an array with length k.

You can check this link If I store a binary tree in an array, how do I avoid the wasted space? to take an idea on how to implement your binary tree in an array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM