Java PriorityQueue with fixed size

后端 未结 7 1046
梦毁少年i
梦毁少年i 2020-12-02 18:38

I am calculating a large number of possible resulting combinations of an algortihm. To sort this combinations I rate them with a double value und store them in PriorityQueue

相关标签:
7条回答
  • 2020-12-02 18:49
    que.add(d);
    if (que.size() > YOUR_LIMIT)
         que.poll();
    

    or did I missunderstand your question?

    edit: forgot to mention that for this to work you probably have to invert your comparTo function since it will throw away the one with highest priority each cycle. (if a is "better" b compare (a, b) should return a positvie number.

    example to keep the biggest numbers use something like this:

    public int compare(Double first, Double second) {
                // keep the biggest values
                return first > second ? 1 : -1;
            }
    
    0 讨论(0)
  • 2020-12-02 18:50

    It seems natural to just keep the top 1000 each time you add an item, but the PriorityQueue doesn't offer anything to achieve that gracefully. Maybe you can, instead of using a PriorityQueue, do something like this in a method:

    List<Double> list = new ArrayList<Double>();
    ...
    list.add(newOutput);
    Collections.sort(list);
    list = list.subList(0, 1000);
    
    0 讨论(0)
  • 2020-12-02 18:51

    Use SortedSet:

    SortedSet<Item> items = new TreeSet<Item>(new Comparator<Item>(...));
    ...
    void addItem(Item newItem) {
        if (items.size() > 100) {
             Item lowest = items.first();
             if (newItem.greaterThan(lowest)) {
                 items.remove(lowest);
             }
        }
    
        items.add(newItem);   
    }
    
    0 讨论(0)
  • 2020-12-02 18:52

    MinMaxPriorityQueue, Google Guava

    There is indeed a class for maintaining a queue that, when adding an item that would exceed the maximum size of the collection, compares the items to find an item to delete and thereby create room: MinMaxPriorityQueue found in Google Guava as of version 8.

    EvictingQueue

    By the way, if you merely want deleting the oldest element without doing any comparison of the objects’ values, Google Guava 15 gained the EvictingQueue class.

    0 讨论(0)
  • 2020-12-02 18:52

    A better approach would be to more tightly moderate what goes on the queue, removing and appending to it as the program runs. It sounds like there would be some room to exclude some the items before you add them on the queue. It would be simpler than reinventing the wheel so to speak.

    0 讨论(0)
  • 2020-12-02 18:59

    Just poll() the queue if its least element is less than (in your case, has worse rating than) the current element.

    static <V extends Comparable<? super V>> 
    PriorityQueue<V> nbest(int n, Iterable<V> valueGenerator) {
        PriorityQueue<V> values = new PriorityQueue<V>();
        for (V value : valueGenerator) {
            if (values.size() == n && value.compareTo(values.peek()) > 0)
                values.poll(); // remove least element, current is better
            if (values.size() < n) // we removed one or haven't filled up, so add
                values.add(value);
        }
        return values;
    }
    

    This assumes that you have some sort of combination class that implements Comparable that compares combinations on their rating.

    Edit: Just to clarify, the Iterable in my example doesn't need to be pre-populated. For example, here's an Iterable<Integer> that will give you all natural numbers an int can represent:

    Iterable<Integer> naturals = new Iterable<Integer>() {
        public Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
                int current = 0;
                @Override
                public boolean hasNext() {
                    return current >= 0;
                }
                @Override
                public Integer next() {
                    return current++;
                }
                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }
            };
        }
    };
    

    Memory consumption is very modest, as you can see - for over 2 billion values, you need two objects (the Iterable and the Iterator) plus one int.

    You can of course rather easily adapt my code so it doesn't use an Iterable - I just used it because it's an elegant way to represent a sequence (also, I've been doing too much Python and C# ☺).

    0 讨论(0)
提交回复
热议问题