очередь приоритетов java не получает правильного порядка в зависимости от частоты hashmap

#java #hashmap #priority-queue

#java #hashmap #приоритетная очередь

Вопрос:

        Map<Integer, Integer> map = new HashMap<>();
        
        for (int n : arr) map.put(n, map.getOrDefault(n, 0)   1);

        PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> map.get(a) - map.get(b));
        for (int n : arr) pq.add(n);
        
        while (!pq.isEmpty()) {
            System.out.print(pq.poll()   " ");
        }
 

Предположим, что входное значение arr равно [4,3,1,1,3,3,2,2]
, и после того, как мы поместим их все в pq и опросим их один за другим.
правильный порядок должен быть 4 1 1 2 2 3 3 3 в порядке частоты.

Но порядок вывода равен 4 1 2 2 1 3 3 3, который не вывел правильный порядок.

Ответ №1:

Порядок правильный. PriorityQueue не гарантирует, что связи будут разорваны, а 1 и 2 связаны:

Если несколько элементов привязаны к наименьшему значению, head является одним из этих элементов — связи разрываются произвольно.

Если вы хотите выбрать порядок для связей, то ваш компаратор должен это сделать. Самый простой способ — написать Comparators.comparingInt(i -> map.get(i)).thenComparingInt(i -> i) , чтобы разорвать связи в порядке возрастания.

Ответ №2:

Оба 1 и 2 появляются дважды в массиве, поэтому, что касается очереди приоритетов, они «равны», поскольку вы просто указываете очереди приоритетов сравнивать только их частоту. Поскольку они равны, они могут отображаться в любом порядке.

Поэтому, чтобы исправить это, вам нужно указать очереди приоритетов, что делать, когда элементы равны. Хотя вы могли бы попытаться добавить эту логику в свой лямбда-код, это проще сделать с comparing thenComparing помощью вызова and:

 PriorityQueue<Integer> pq = new PriorityQueue<>(
    Comparator.<Integer, Integer>comparing(map::get)
        .thenComparing(Function.identity())
);
 

Это означает «сравните значение, которое вы получаете с карты, затем сравните само число». Это означает, что она будет упорядочивать 1 до 2, даже если оба 1 и 2 произошли дважды.

Ответ №3:

Более простой способ добиться того же-

PriorityQueue<Map.Entry<Integer,Integer>> pq=new PriorityQueue<>(a,b) -> map.get(a)==map.get(b) ? b-a: map.get(b)-map.get(a));

Здесь вы сначала проверяете, одинаковы ли значения карты для соответствующего ключа или нет, если одинаковые, затем сортируете на основе ключа

если не то же самое, просто отсортируйте на основе частоты

Комментарии:

1. ИМХО, это всего лишь немного другая версия ответа Sweeper.