Сортировка подмассивов в случайном порядке

#java #algorithm #sorting #collections #shuffle

#java #алгоритм #сортировка #Коллекции #перемешивание

Вопрос:

Допустим, у меня есть объект с одним значимым критерием и, возможно, с некоторыми другими данными.

 class MyObject {
    int criteria;
    String otherData;
}
  

Я хочу «отсортировать в случайном порядке» список таким образом, чтобы с учетом данных x, y, так что x является критерием, а y — другими данными, все похожие x группируются (и сортируются), но внутри подгруппы они перемешиваются

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

 / 1s first|/ 2s next |/ then 3s 
-----------------------------------
1,a 1,b 1,c 2,d 2,e 2,f 3,g 3,h 3,i // other data is in
1,a 1,c 1,b 2,e 2,d 2,f 3,i 3,h 3,g // a random order
1,c 1,a 1,b 2,d 2,f 2,e 3,h 3,i 3,g // within the subgroup
1,b 1,c 1,c 2,e 2,d 2,f 3,g 3,h 3,i 
  

Мой текущий план состоит в том, чтобы создать сопоставимый, который сравнивает только первые критерии. Тогда моя «сортировка в случайном порядке» могла бы просто

 list.shuffle(); // get a random ordering
list.sort(); // now group by criteria, leaving the others in a still random state
  

Мой вопрос в том, является ли это наиболее эффективным способом сделать это? Действительно ли это достигнет моей цели? Есть ли какой-то шаблон, который может возникнуть из этого? Если да, то что?

Ответ №1:

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

Если вы хотите написать код, который более явно выражает ваши намерения, вы можете вставить значения в TreeMap<Integer, List<MyObject>> , сгруппировав все значения данного целого числа в один список. Затем выполните итерацию по содержимому карты в порядке следования ключей (от наименьшего к наибольшему), перетасовывая каждый подсписок, а затем сбрасывая его содержимое в конечный выходной список. На мой взгляд, этот подход более «очевидно правильный», но я считаю, что ваш работает так же хорошо.

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

1. Компаратор не знает о несортированных полях. Таким образом, я совершенно уверен, что нестабильная сортировка не может привести к смещению здесь.

2. Да, я согласен. Все, что я имел в виду, это то, что если вы хотите привести формальный аргумент, вам нужно было бы сказать, что (а) сортировка имеет перестановку без учета других полей и (б) что равномерная перестановка порядка несмещенной случайной перетасовки также является несмещенной случайной перетасовкой. Эти два факта кажутся очевидными, но они делают аргумент немного более тонким.

Ответ №2:

Единственная оптимизация, которую я вижу в вашем подходе, заключалась бы в использовании какого-то итератора перетасовки вместо фактического перетасовки данных. Но это не изменит сложность вашего алгоритма, потому что стоимость перетасовки в худшем случае линейна, а сортировка в лучшем случае равна n log (n)

Ответ №3:

Подумайте о том, что вы пытаетесь сделать, прежде чем думать о реализации, и попытайтесь найти подходящее из существующих классов JDK.

Я бы использовал, Map<Integer, List<MyObject>> который сразу решил бы проблему группировки, тогда я мог бы Collections.shuffle() списки, и если бы я действительно хотел единый список, я мог бы сбросить списки в значениях карты в один список:

 Map<Integer, List<MyObject>> map = new HashMap<Integer, List<MyObject>>();
...
List oneList = new ArrayList<MyObject>(map.values());
for (List<?> list : map.values())
    oneList.addAll(list);
  

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

1. Я думал об этом, но это самый критичный по времени цикл в приложении. Он должен переупорядочивать приоритеты на каждой итерации, и для этого мне пришлось бы каждый раз воссоздавать всю структуру карты / списка. Я также вижу, что мне пришлось бы отсортировать oneList , чтобы убедиться, что все они пришли в правильном порядке, поскольку values() ему не присвоен порядок.

2. Я должен также отметить, что длина списка не может быть больше 10, что еще больше увеличивает величину этих накладных расходов.

3. Вы можете использовать упорядоченную карту для поддержания порядка по int criteria . Кроме того, я предлагаю вам сохранить карту на полную ставку и отображать список только тогда, когда вам это абсолютно необходимо, или измените свое приложение для работы с картой. И, кстати, это должно быть criterion , а не criteria : criteria множественное число criterion , и у вас есть только одно int , если это не битовая маска 🙂

4. Int представляет набор всех критериев, который содержит один элемент. 🙂 В любом случае, к сожалению, он должен отображаться в виде списка с каждой итерацией. Это должно быть доступно для алгоритмов принятия решений, чтобы они могли правильно принимать свои решения. Если у меня нет списка для принятия ими решения, они могут получить другой результат даже на одной итерации, чего они не должны.