将priorityQueue更改为max priorityqueue


123

我在Integers的Java中有优先级队列:

 PriorityQueue<Integer> pq= new PriorityQueue<Integer>();

当我打电话时,pq.poll()我得到了最小的元素。

问题:如何更改代码以获取最大元素?


4
我认为您应该使用为此接收比较器的构造函数。使用Collections.reverseOrder获得反向的比较器。
Edwin Dalorzo 2012年

1
您需要通过一个比较器。看到stackoverflow.com/questions/683041/...
安纳金·天行者

Answers:


232

这样吧:

PriorityQueue<Integer> queue = new PriorityQueue<>(10, Collections.reverseOrder());
queue.offer(1);
queue.offer(2);
queue.offer(3);
//...

Integer val = null;
while( (val = queue.poll()) != null) {
    System.out.println(val);
}

Collections.reverseOrder()提供了一个Comparator将在元素进行排序PriorityQueue在这种情况下,在该oposite为了自己的自然顺序。


14
Collections.reverseOrder()也是比较器的重载,因此如果您比较自定义对象,它也可以工作。
飞羊

14
Java 8的PriorityQueue具有一个新的构造函数,该构造函数仅将比较器作为参数PriorityQueue(Comparator<? super E> comparator)
abhisheknirmal

75

从Java 8开始可以使用lambda表达式。

下面的代码将打印10个较大的代码。

// There is overflow problem when using simple lambda as comparator, as pointed out by Фима Гирин.
// PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> y - x);

PriorityQueue<Integer> pq =new PriorityQueue<>((x, y) -> Integer.compare(y, x));

pq.add(10);
pq.add(5);
System.out.println(pq.peek());

lambda函数将两个Integer作为输入参数,将它们彼此相减,然后返回算术结果。lambda函数实现功能接口Comparator<T>。(这是就地使用的,与匿名类或离散实现相反。)


lambda函数,命名其输入参数x和y并返回yx,这基本上是int比较器类所做的,除了返回xy
Edi Bice17年

15
(x, y) -> y - x由于溢出,类似的比较器可能不适用于长整数。例如,数字y = Integer.MIN_VALUE,而x = 5则得出正数。最好使用 new PriorityQueue<>((x, y) -> Integer.compare(y, x))。虽然,@ Edwin Dalorzo可以使用更好的解决方案Collections.reverseOrder()
ФимаГирин

1
@ФимаГирин是的。-2147483648-1变成2147483647
沉广通

27

您可以提供一个自定义Comparator对象,以相反的顺序对元素进行排名:

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(defaultSize, new Comparator<Integer>() {
    public int compare(Integer lhs, Integer rhs) {
        if (lhs < rhs) return +1;
        if (lhs.equals(rhs)) return 0;
        return -1;
    }
});

现在,优先级队列将撤消其所有比较,因此您将获得最大元素而不是最小元素。

希望这可以帮助!


5
也许对于最大优先级q lhs <rhs returs +1; 经过我的测试,您在此处写的是最小q
sivi'3

对于反向打印,也就是说,如果要在优先级队列中首先打印最高的元素,则应该为if (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha我相信我拥有的代码等同于您要发布的代码。我只是使用了大于关系而不是小于关系。
templatetypedef

4
实际上,我的错误..我的意思是应该像这样:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu好收获-现在已解决!
templatetypedef

14
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
  new Comparator<Integer> () {
    public int compare(Integer a, Integer b) {
       return b - a;
    }
  }
);

问题是什么 ?
CMedina '16

这是完美的,并且完全可以通过将最小堆变为最大堆来完成所要求的操作。
卡姆兰

2
使用b-a可引起overflow所以应避免使用它并应使用Collections.reverseOrder();作为比较器或更换用Ba Integer.compare(a,b);已经在添加Java 8
YUG辛格

10

在Java 8+中,您可以通过以下方法之一创建最大优先级队列:

方法1:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Collections.reverseOrder()); 

方法2:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b - a); 

方法3:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b.compareTo(a)); 

8

优先级队列的元素是根据其自然排序或在队列构建时提供的比较器进行排序的。

比较器应重写比较方法。

int compare(T o1, T o2)

默认比较方法将返回负整数,零或正整数,因为第一个参数小于,等于或大于第二个参数。

Java提供的Default PriorityQueue是Min-Heap,如果要最大堆,则代码如下

public class Sample {
    public static void main(String[] args) {
        PriorityQueue<Integer> q = new PriorityQueue<Integer>(new Comparator<Integer>() {

            public int compare(Integer lhs, Integer rhs) {
                if(lhs<rhs) return +1;
                if(lhs>rhs) return -1;
                return 0;
            }
        });
        q.add(13);
        q.add(4);q.add(14);q.add(-4);q.add(1);
        while (!q.isEmpty()) {
            System.out.println(q.poll());
        }
    }

}

参考:https : //docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#comparator()


4

这是Java中的Max-Heap示例:

PriorityQueue<Integer> pq1= new PriorityQueue<Integer>(10, new Comparator<Integer>() {
public int compare(Integer x, Integer y) {
if (x < y) return 1;
if (x > y) return -1;
return 0;
}
});
pq1.add(5);
pq1.add(10);
pq1.add(-1);
System.out.println("Peek: "+pq1.peek());

输出将是10


4

这可以通过Java 8中的以下代码实现,该代码引入了仅使用比较器的构造函数。

PriorityQueue<Integer> maxPriorityQ = new PriorityQueue<Integer>(Collections.reverseOrder());

3

您可以使用MinMaxPriorityQueue(它是Guava库的一部分): 这是文档。而不是poll(),您需要调用pollLast()方法。


3

将PriorityQueue更改为MAX PriorityQueue方法1:队列pq = new PriorityQueue <>(Collections.reverseOrder()); 方法2:队列pq1 = new PriorityQueue <>(((a,b)-> b-a); 让我们看几个例子:

public class Example1 {
    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        pq.addAll(ints);
        System.out.println("Priority Queue => " + pq);
        System.out.println("Max element in the list => " + pq.peek());
        System.out.println("......................");
        // another way
        Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
        pq1.addAll(ints);
        System.out.println("Priority Queue => " + pq1);
        System.out.println("Max element in the list => " + pq1.peek());
        /* OUTPUT
          Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
          Max element in the list => 888
          ......................
           Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
           Max element in the list => 888

         */


    }
}

让我们接受一个著名的访谈问题:使用PriorityQueue的数组中第K个最大元素

public class KthLargestElement_1{
    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        int k = 3;
        Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        pq.addAll(ints);
        System.out.println("Priority Queue => " + pq);
        System.out.println("Max element in the list => " + pq.peek());
        while (--k > 0) {
            pq.poll();
        } // while
        System.out.println("Third largest => " + pq.peek());
/*
 Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
Third largest => 666

 */
    }
}

其他方式 :

public class KthLargestElement_2 {
    public static void main(String[] args) {
        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        int k = 3;

        Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
        pq1.addAll(ints);
        System.out.println("Priority Queue => " + pq1);
        System.out.println("Max element in the list => " + pq1.peek());
        while (--k > 0) {
            pq1.poll();
        } // while
        System.out.println("Third largest => " + pq1.peek());
        /*
          Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222] 
          Max element in the list => 888 
          Third largest => 666

         */
    }
}

我们可以看到,两者给出的结果相同。


3

这可以通过使用

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());

1

我只是在两个堆的最小和最大堆上对两个比较器运行了蒙特卡洛仿真,它们都得到相同的结果:

这些是我使用的最大比较器:

(A)集合内置比较器

 PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(Collections.reverseOrder());

(B)自定义比较器

PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(new Comparator<Integer>() {
    int compare(Integer lhs, Integer rhs) {
        if (rhs > lhs) return +1;
        if (rhs < lhs) return -1;
        return 0;
    }
});

对于反向打印,也就是说,如果要在优先级队列中首先打印最高的元素,则应该是if (rhs < lhs) return +1;(rhs> lhs)返回-1;
Tia

您可以根据需要进行编辑。我没有时间确认你写的内容。在我的设置中,我写的是正确的
sivi

1

您可以尝试类似:

PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> -1 * Integer.compare(x, y));

这对您可能拥有的任何其他基本比较功能都适用。



0

您可以尝试使用带有反向符号的元素。例如:添加a = 2&b = 5,然后轮询b = 5。

PriorityQueue<Integer>  pq = new PriorityQueue<>();
pq.add(-a);
pq.add(-b);
System.out.print(-pq.poll());

轮询队列的开头后,请反转符号以供使用。这将打印5(较大的元素)。可以在幼稚的实现中使用。绝对不是可靠的解决方案。我不推荐。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.