Java - Поиск чего-то быстрее, чем PriorityQueue

Если можно загрузиться в Ubuntu, попробуйте sudo личинку обновления, это покажет Вам, что ОС Вы установили ту личинку, может найти. Если это не находит Windows, спросите снова. Раздел NTFS обнаруживается хорошо в gparted?

6
задан Roland Ewald 31 August 2009 в 20:00
поделиться

4 ответа

Очередь приоритетов на основе кучи - хорошая структура данных для этой проблемы. В качестве проверки работоспособности убедитесь, что вы правильно используете очередь.

Если вам нужны элементы с наибольшим весом, используйте очередь min , где вершина кучи является наименьшим элементом. Добавление каждого элемента в очередь max-queue и проверка верхних M элементов по завершении неэффективно.

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

В некоторых кучах есть API-интерфейсы быстрого доступа для замены верхней части кучи, но Java ' s Очередь - нет. Даже в этом случае сложность большого О остается той же.

6
ответ дан 8 December 2019 в 18:39
поделиться

В дополнение к предлагаемому алгоритму «заглянуть в верхнюю часть кучи», который дает вам сложность O (n log m) для получения верхних m из n элементов, вот еще два решения.

Решение 1. Используйте кучу Фибоначчи.

Реализация PriorityQueue в JDK представляет собой сбалансированную двоичную кучу. Вы должны иметь возможность выжать больше производительности из реализации кучи Фибоначчи . Он будет иметь амортизированную вставку с постоянным временем, в то время как вставка в двоичную кучу имеет сложность Ω (log n) в размере кучи. Если вы делаете это для каждого элемента, то вы находитесь в Ω (n log n). Сложность поиска топ-m из n элементов с помощью кучи Fib составляет O (n + m log n). Объедините это с предложением вставлять в кучу только m элементов, и вы получите O (n + m log m), что так же близко к линейному времени, как и вы. re going to get.

Решение 2: Просмотрите список M раз.

Вы должны суметь получить k-й по величине элемент в наборе за O (n) раз. Просто прочтите все в списке и сделайте следующее:

kthLargest(k, xs)
  Pick a random pivot element p from the list
    (the first one will do if your list is already random).
  Go over the set once and group it into two lists.
     Left: smaller than p. 
     Right: Larger or equal to p.
  If the Right list is shorter than k, return kthLargest(k - right.size, Left)
  If the Right list is longer than k, return kthLargest(k, right)
  Otherwise, return p.

Это дает вам O (n) времени. Выполнив это m раз, вы сможете получить топ-m объектов в своем наборе за время O (нм), которое будет строго меньше, чем n log n для достаточно больших n и достаточно малых m. Например, получение топ-10 из миллиона элементов займет вдвое меньше времени, чем использование очереди с приоритетом двоичной кучи, при прочих равных условиях.

вы должны иметь возможность получить объекты top-m в своем наборе за время O (нм), которое будет строго меньше, чем n log n для достаточно больших n и достаточно малых m. Например, получение топ-10 из миллиона элементов займет вдвое меньше времени, чем использование очереди с приоритетом двоичной кучи, при прочих равных условиях.

вы должны иметь возможность получить объекты top-m в своем наборе за время O (нм), которое будет строго меньше, чем n log n для достаточно больших n и достаточно малых m. Например, получение топ-10 из миллиона элементов займет вдвое меньше времени, чем использование очереди с приоритетом двоичной кучи, при прочих равных.

5
ответ дан 8 December 2019 в 18:39
поделиться

Если M достаточно мало, то сортировка всех элементов может тратить много вычислительного времени. Вы можете поместить только первые объекты M в приоритетную очередь (например, кучу, минимальный элемент сверху), а затем выполнить итерацию по остальным элементам: каждый раз, когда элемент больше вершины кучи, удалите верх и нажмите новый элемент в кучу.

В качестве альтернативы, вы можете выполнить итерацию по всему массиву один раз, чтобы найти статистическое пороговое значение, для которого вы можете быть уверены, что существует более M объектов с большим значением (потребуются некоторые предположения относительно значений, например, если они обычно распределены). Затем вы можете ограничить сортировку всеми элементами с большим значением.

2
ответ дан 8 December 2019 в 18:39
поделиться

@Tnay: У вас есть возражение по поводу того, что сравнение не выполняется. К сожалению, ваш пример кода все еще выполняет его. Это решает проблему:

public int compare(ListElement i, ListElement j) {
    return i.getValue() - j.getValue();
}

Кроме того, ни ваш метод сравнения, ни метод сравнения BigG не являются строго правильными, поскольку они никогда не возвращают 0. Это может быть проблемой с некоторыми алгоритмами сортировки, что является очень сложной ошибкой, поскольку она только появляется если вы переключаетесь на другую реализацию.

Из документы Java :

Разработчик должен убедиться, что sgn (compare (x, y)) == -sgn (compare (y, x)) для всех x и y.

Это может или не может обеспечить значительное ускорение с постоянным коэффициентом. Если вы объедините это с решением Эриксона, вероятно, будет сложно сделать это быстрее (в зависимости от размера M). Если M очень велико, наиболее эффективным решением, вероятно, является сортировка всех элементов с помощью встроенной в Java функции qsort в массиве и обрезание одного конца массива в конце.

0
ответ дан 8 December 2019 в 18:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: