Подтвердить что ты не робот

Поиск N-го элемента несортированного списка без сортировки списка

Эй. У меня очень большой массив, и я хочу найти N-е наибольшее значение. Тривиально я могу отсортировать массив, а затем взять элемент Nth, но меня интересует только один элемент, поэтому, вероятно, лучший способ, чем сортировка всего массива...

4b9b3361

Ответ 1

Для сортировки потребуется минимальное время выполнения O (nlogn). Существуют очень эффективные алгоритмы выбора, которые могут решить вашу проблему в линейном времени.

Partition-based selection (иногда Quick select), основанный на идее быстрой сортировки (рекурсивное разбиение), является хорошим решением (см. ссылку для псевдокода + Другой пример).

Ответ 2

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

import heapq

def nth_largest(n, iter):
    return heapq.nlargest(n, iter)[-1]

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

>>> import random
>>> iter = [random.randint(0,1000) for i in range(100)]
>>> n = 10
>>> nth_largest(n, iter)
920

Подтвердить результат путем сортировки:

>>> list(sorted(iter))[-10]
920

Ответ 3

Вы можете выполнить итерацию всей последовательности, поддерживая список из 5 самых больших найденных значений (это будет O (n)). При этом я считаю, что просто отсортировать список.

Ответ 4

Простая модифицированная быстродействующая сортировка очень хорошо работает на практике. Он имеет среднее время работы, пропорциональное N (хотя наихудшее время неудачи - O (N ^ 2)).

Продолжайте работать как быстрая сортировка. Выберите случайное значение случайным образом, затем выполните поток через свои значения и посмотрите, находятся ли они выше или ниже этого значения поворота и помещают их в два бункера на основе этого сравнения. В quicksort вы затем рекурсивно сортируете каждый из этих двух бункеров. Но для вычисления N-го наивысшего значения вам нужно всего лишь сортировать ОДИН из бункеров. Население каждого бункера сообщает вам, какой бит держит ваше n-е самое высокое значение. Так, например, если вы хотите 125-е наивысшее значение, и вы сортируете на два бункера, которые имеют 75 в "высоком" бункере и 150 в "низком" бункере, вы можете игнорировать большой бит и просто перейти к поиску 125-75 = 50-е наивысшее значение только в одном разряде.

Ответ 5

Вы можете попробовать медианный метод Medians - это скорость O (N).

Ответ 6

Используйте heapsort. Он только частично заказывает список, пока вы не вычеркните элементы.

Ответ 7

Вы действительно хотите создать список "top-N" и выбрать тот, который находится в конце этого списка.

Итак, вы можете сканировать массив один раз и вставлять в пустой список, когда элемент largeArray больше, чем последний элемент списка top-N, а затем отбрасывает последний элемент.

После завершения сканирования выберите последний элемент в списке top-N.

Пример для int и N = 5:

int[] top5 = new int[5]();
top5[0] = top5[1] = top5[2] = top5[3] = top5[4] = 0x80000000; // or your min value

for(int i = 0; i < largeArray.length; i++) {
    if(largeArray[i] > top5[4]) {
       // insert into top5:
       top5[4] = largeArray[i];

       // resort:
       quickSort(top5);
    }
}

Ответ 8

Как говорили люди, вы можете ходить по списку после отслеживания K самых больших значений. Если K велико, этот алгоритм будет близок к O (n 2).

Однако вы можете сохранить самые большие значения Kth в качестве двоичного дерева, и операция станет O (n log k).

Согласно Википедии, это лучший алгоритм выбора:

 function findFirstK(list, left, right, k)
     if right > left
         select pivotIndex between left and right
         pivotNewIndex := partition(list, left, right, pivotIndex)
         if pivotNewIndex > k  // new condition
             findFirstK(list, left, pivotNewIndex-1, k)
         if pivotNewIndex < k
             findFirstK(list, pivotNewIndex+1, right, k)

Его сложность O (n)

Ответ 9

Одна вещь, которую вы должны сделать, если это в производственном коде, - это тест с образцами ваших данных. Например, вы можете рассмотреть массивы размером 1000 или 10000 элементов, а также создать метод быстрого выбора из рецепта.

Скомпилированный характер отсортированных и несколько скрытых и постоянно меняющихся оптимизаций делает его быстрее, чем написанный на питоне метод quickselect для наборов данных малого и среднего размера (< 1,000,000 элементов). Кроме того, вы можете найти, когда вы увеличиваете размер массива, превышающего эту величину, память более эффективно обрабатывается в собственном коде, и преимущество сохраняется.

Таким образом, даже если quickselect - это O (n) vs sorted O (nlogn), это не учитывает, сколько фактических инструкций машинного кода обрабатывает каждый n элементов, любые воздействия на конвейерную обработку, использование кэшей процессора и другие вещи, которые создатели и сторонники сортировки будут испепеляться в коде python.