2015-12-28 3 views
0

Я пытаюсь сортировать карту Map<Integer,Set<Integer>>, которая хранит элементы, отсортированные по size() установленного значения.Карта, отсортированная по размеру коллекции значений

На практике это карта узла с другими узлами, подключенными к этому узлу. Я хочу быстро (O (logn)) получить доступ к узлу с наибольшим количеством ребер без необходимости сортировать каждый раз.

Например, порядок должен быть:

3 => {1,2,4,5} 
12 => {1,2,3} 
14 => {3,2,3} 
65 => {3,8} 
6 => {2} 
2 => {5} 

С TreeMap не будет делать это, так как я не могу сортировать на основе значений, я, вероятно, нужно свернуть что-то обычай.

EDIT: Размер набора действительно может измениться, которые могут чрезмерно усложнять еще больше

Что бы самый простой способ для достижения этой цели?

+1

Что значит «TreeMap» не будет делать? Вы можете использовать пользовательский Компаратор. – markspace

+0

@markspace Только компаратор позволяет сортировать по ключу (если я не хочу принять еще один уродливый/ненадежный хак/решение) –

+1

Обратный ключ и значение. Вы сказали, что хотите посмотреть по размеру правильно? – markspace

ответ

1

Вот пример сортировки, как использовать два набора для этого. Один набор сортируется по Set :: size, а другой - это обычная карта с индексом integer. Чтобы использовать это, вы должны хранить одни и те же пары ключ/значение на обеих картах.

Я не уверен, рекомендую ли я попытаться сделать одну карту из этого. У него есть два поиска по индексу и по размеру, поэтому он не работает как обычная карта. Это будет зависеть от вашей модели использования.

package quicktest; 

import static java.util.Comparator.comparing; 
import java.util.HashSet; 
import java.util.Set; 
import java.util.TreeMap; 

public class TreeMapTest 
{ 
    public static void main(String[] args) { 
     TreeMap<Integer,Set<Integer>> index = new TreeMap<>(); 
     TreeMap<Set<Integer>,Integer> size = new TreeMap<>(comparing(Set::size)); 

     for(int i = 0; i < 5; i++) { 
     Set<Integer> set = new HashSet<>(); 
     for(int val = 0; val <= i; val++) { 
      set.add(val); 
     } 
     index.put(i, set); 
     size.put(set, i); 
     } 
     System.out.println(size.lastEntry()); // largest set size 
     System.out.println(index.get(2)); // random index 
    } 
} 
+1

Это будет работать, только если мы не изменим Set.size после вставки, потому что ключ сортировки (размер) изменен. Вам нужно надлежащее управление при добавлении/удалении элементов из каждого набора. –

+0

Или сделайте копию наборов, прежде чем вставлять их, чтобы последующие изменения не влияли на уже сохраненные наборы. Я был бы склонен идти по этому маршруту. – markspace

+0

Но OP хочет обновить индексную карту после вставки; так что получите, измените (добавьте/удалите элементы), затем сохраните обратно –

1

Как насчет этого?

public class MapAndPriority { 
    Map<Integer, Set<Integer>> sets = new HashMap<Integer, Set<Integer>>(); 
    PriorityQueue<Set<Integer>> byLength = new PriorityQueue<Set<Integer>>(1, new Comparator<Set<Integer>>() { 
     @Override 
     public int compare(Set<Integer> o1, Set<Integer> o2) { 
      // Compare in the reverse order! 
      return o2.size() - o1.size(); 
     } 
    }); 

    public void add(int i, Set<Integer> set) { 
     sets.put(i, set); 
     byLength.offer(set); // or Add, depending on the behavior you want 
    } 

    public Set<Integer> get(int i) { 
     return sets.get(i); 
    } 

    public Set<Integer> mostNodes() { 
     return byLength.peek(); 
    } 

    public void remove(int i) { 
     // sets.remove will return the removed set, so that will be removed from byLength. 
     // Need to handle case when i does not exist as a key in sets 
     byLength.remove(sets.remove(i)); 

    } 
} 

Если я понимаю, что вы хотите, то это будет:

  1. Добавить новые наборы в о (NLog (п))
  2. Regular карту get()
  3. Получит самый большой набор (mostNodes()) in o (log (n))

То, что я сделал, это разместить все наборы в очереди приоритетов (вдоль карты) а затем предоставить приоритетную очередь компаратору, который сравнивается на основе размеров, так что меньший размер «больше». Таким образом, когда вы вызываете peek(), он вернет «минимальное» значение в очереди приоритетов, которое из-за нашего компаратора будет самым длинным. Я не занимался всевозможными краевыми случаями (например, удалять, когда пустым).

Вы можете ознакомиться с documentation для получения более подробной информации и о сложности.

+0

Нашел небольшую ошибку в моей реализации. Если вы измените наборы после вставки, то вызов 'mostNodes' не будет работать. Если вы хотите изменить наборы после вставки, вы можете добавить еще один метод в «MapAndPriority», который добавляет/удаляет элементы из набора. Затем потребуется удалить набор из очереди приоритетов, изменить его, а затем повторно добавить. – Ginandi

+0

Ваше предложение по исправлению будет работать только в том случае, если вы уверены, что никто не имеет доступа к любому из наборов и не меняет свой размер, не вызывая предлагаемый метод add/remove. Я предполагаю, что шаблон Observer обеспечит более правильное решение этой проблемы. –

+0

Ну, не зная большей картины, я не могу защитить свое предложение. Но в целом вы можете выставлять только этот класс, а получатели возвращают только копии. – Ginandi

Смежные вопросы