Извлечение данного числа самых высоких значений в списке

StackOverflow https://stackoverflow.com/questions/2625229

Вопрос

Я хочу отобразить фиксированное количество элементов на веб-странице в соответствии с их соответствующим весом (представлена Integer). Список, где найдены эти предметы, могут быть практически любого размера.

Первое решение, которое приходит к уму, это сделать Collections.sort() и чтобы получить предметы один за другим, пройдя через List. Отказ Есть ли более элегантное решение, хотя это можно было использовать для подготовления, скажем, восемь лучших предметов?

Это было полезно?

Решение

Просто иди Collections.sort(..). Отказ Это достаточно эффективно.

Этот алгоритм предлагает гарантированную производительность N log (n).

Ты могу Попробуйте реализовать что-то более эффективное Для вашего конкретного корпуса Если вы знаете некоторые отличительные свойства вашего списка, но это не было бы оправданным. Кроме того, если ваш список исходит из базы данных, например, вы можете LIMIT Это и заказать его там вместо в коде.

Другие советы

Ваши варианты:

  1. Делать линейный Поиск, поддержание топных весов, найденных по пути. Это должно быть быстрее, чем сортировка длинного списка, если по какой-то причине вы не можете повторно использовать результаты сортировки между отображением страницы (например, список быстро меняется).

    Обновление: я постоянно поправляется на линейный поиск, обязательно быть лучше, чем сортировка. Смотрите статью Википедия »Selection_algorithm - выбор k наименьшего или самых больших элементов«Для лучших алгоритмов выбора.

  2. Вручную поддерживать а List (Оригинальный или параллельный) отсортирован в порядке веса. Вы можете использовать методы, такие как Коллекции. BINAYSearch () Чтобы определить, где вставить каждый новый элемент.

  3. Поддерживать а List (Оригинальный или параллельный) отсортирован в порядке веса, позвонив Коллекции .sort () После каждой модификации пакетных модификаций или незадолго до отображения (возможно, поддерживая флаг модификации, чтобы избежать сортировки уже сортированного списка).

  4. Используйте структуру данных, которая поддерживает отсортированный вес для вас: Очередная очередь, набор дерева, и т. Д. Вы также можете создать свою собственную структуру данных.

  5. Вручную поддерживать вторую (возможно, заказываемую весом) структуру данных Top N элементов. Эта структура данных обновляется в любое время, что исходная структура данных модифицирована. Вы можете создать свою собственную структуру данных, чтобы обернуть оригинальный список и этот «топ-н-кеш» вместе.

Вы могли бы использовать макс-куча.

Если ваши данные возникают из базы данных, поместите индекс в этом столбце и используйте Order By и Top или ограничить, чтобы получить только записи, которые вам нужно отображать.

с использованием доллар:

List<Integer> topTen = $(list).sort().slice(10).toList();

без использования доллара, вы должны sort() это использует Collections.sort(), затем получите первые n элементов, используя list.sublist(0, n).

Поскольку вы говорите список элементов, из которых для извлечения этих топ не может быть любого размера, и поэтому может быть большой, я предполагаю, что я увеличил простой sort() Ответы выше (которые полностью подходят для разумно-размера входных данных), предлагая большую часть работы здесь, находит TOP N - тогда сортировка этих n тривиальна. То есть:

Queue<Integer> topN = new PriorityQueue<Integer>(n);
for (Integer item : input) {
  if (topN.size() < n) {
    topN.add(item);        
  } else if (item > topN.peek()) {
    topN.add(item);          
    topN.poll();
  }
}

List<Integer> result = new ArrayList<Integer>(n);
result.addAll(topN);
Collections.sort(result, Collections.reverseOrder());

Куча здесь (мин-куча), по меньшей мере, ограничена по размеру. Там нет реальной необходимости сделать кучу из всех ваших предметов.

Нет, не совсем. По крайней мере, не используя встроенные методы Java.

Есть умные способы получить самые высокие (или самые низкие) количество элементов из списка быстрее, чем O(n*log(n)) Эксплуатация, но это потребует от вас, чтобы вручить этот раствор. Если количество предметов остается относительно низким (не более пару сотен), сортируя его с помощью Collections.sort() а затем схватить топ N чисел - это путь к ИМО.

Зависит от того, сколько. Давайте определим как общее количество клавиш, а m как число, которое вы хотите отобразить.
Сортировка всей вещи: O(nlogn)
Сканирование массива каждый раз для следующего наивысшего числа: O(n*m)
Таким образом, вопрос в том, каково отношение между n м?
Если m < log n, сканирование будет более эффективным.
Иначе, m >= log n, что означает сортировку будет лучше. (Поскольку для крайнего случая m = log n На самом деле это не имеет значения, но сортировка также даст вам преимущество, ну, сортируя массив, который всегда приятно.

Если размер списка N, и количество элементов, которые необходимо извлечено, это K, вам необходимо позвонить в список в списке, что преобразует список (который должен быть наименочным, например, массивом) в очередь приоритета. (См. Функция HeaPify In http://en.wikipedia.org/wiki/heapsort.)

Получение элемента в верхней части кучи (максимальный элемент) принимает o (lg n). Так что ваше общее время будет:

O (n + k lg n)

что лучше, чем o (n lg n), предполагая, что k намного меньше N.

Если удерживайте отсортированный массив или использование другой структуры данных, не вариант, вы можете попробовать что-то вроде следующего. Время o похоже на сортировку большого массива, но на практике это должно быть более эффективно.

small_array = big_array.slice( number_of_items_to_find );
small_array.sort();
least_found_value = small_array.get(0).value;

for ( item in big_array ) {  // needs to skip first few items
  if ( item.value > least_found_value ) {
    small_array.remove(0);
    small_array.insert_sorted(item);
    least_found_value = small_array.get(0).value;
  }
}

Small_Array может быть объектом [], а внутренний цикл можно сделать с помощью замены вместо того, чтобы фактически удалить и вставлять в массив.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top