Is there a PriorityQueue implementation with fixed capacity and custom comparator?

后端 未结 9 2525
后悔当初
后悔当初 2020-11-28 05:59

Related questions:

  • Java PriorityQueue with fixed size
  • How do I use a PriorityQueue?
  • get indexes of n smallest elements in an array
9条回答
  •  余生分开走
    2020-11-28 06:45

    Below is the implementation I used before. Complies with Peter's suggestion.

     public @interface NonThreadSafe {
     }
    
    /**
     * A priority queue implementation with a fixed size based on a {@link TreeMap}.
     * The number of elements in the queue will be at most {@code maxSize}.
     * Once the number of elements in the queue reaches {@code maxSize}, trying to add a new element
     * will remove the greatest element in the queue if the new element is less than or equal to
     * the current greatest element. The queue will not be modified otherwise.
     */
    @NonThreadSafe
    public static class FixedSizePriorityQueue {
        private final TreeSet treeSet; /* backing data structure */
        private final Comparator comparator;
        private final int maxSize;
    
        /**
         * Constructs a {@link FixedSizePriorityQueue} with the specified {@code maxSize}
         * and {@code comparator}.
         *
         * @param maxSize    - The maximum size the queue can reach, must be a positive integer.
         * @param comparator - The comparator to be used to compare the elements in the queue, must be non-null.
         */
        public FixedSizePriorityQueue(final int maxSize, final Comparator comparator) {
            super();
            if (maxSize <= 0) {
                throw new IllegalArgumentException("maxSize = " + maxSize + "; expected a positive integer.");
            }
            if (comparator == null) {
                throw new NullPointerException("Comparator is null.");
            }
            this.treeSet = new TreeSet(comparator);
            this.comparator = treeSet.comparator();
            this.maxSize = maxSize;
        }
    
        /**
         * Adds an element to the queue. If the queue contains {@code maxSize} elements, {@code e} will
         * be compared to the greatest element in the queue using {@code comparator}.
         * If {@code e} is less than or equal to the greatest element, that element will be removed and
         * {@code e} will be added instead. Otherwise, the queue will not be modified
         * and {@code e} will not be added.
         *
         * @param e - Element to be added, must be non-null.
         */
        public void add(final E e) {
            if (e == null) {
                throw new NullPointerException("e is null.");
            }
            if (maxSize <= treeSet.size()) {
                final E firstElm = treeSet.first();
                if (comparator.compare(e, firstElm) < 1) {
                    return;
                } else {
                    treeSet.pollFirst();
                }
            }
            treeSet.add(e);
        }
    
        /**
         * @return Returns a sorted view of the queue as a {@link Collections#unmodifiableList(java.util.List)}
         *         unmodifiableList.
         */
        public List asList() {
            return Collections.unmodifiableList(new ArrayList(treeSet));
        }
    }
    

    I would appreciate any feedback btw.

    EDIT: It seems like using a TreeSet is not very efficient after all because the calls to first() seem to take sublinear time. I changed the TreeSet to a PriorityQueue. The modified add() method looks like this:

       /**
         * Adds an element to the queue. If the queue contains {@code maxSize} elements, {@code e} will
         * be compared to the lowest element in the queue using {@code comparator}.
         * If {@code e} is greater than or equal to the lowest element, that element will be removed and
         * {@code e} will be added instead. Otherwise, the queue will not be modified
         * and {@code e} will not be added.
         *
         * @param e - Element to be added, must be non-null.
         */
        public void add(final E e) {
            if (e == null) {
                throw new NullPointerException("e is null.");
            }
            if (maxSize <= priorityQueue.size()) {
                final E firstElm = priorityQueue.peek();
                if (comparator.compare(e, firstElm) < 1) {
                    return;
                } else {
                    priorityQueue.poll();
                }
            }
            priorityQueue.add(e);
        }
    

提交回复
热议问题