Ответ 1
Существует несколько различных алгоритмов выбора, начиная с гораздо более простого quickselect (ожидаемого O (n), наихудшего варианта O (n 2)) с более сложным алгоритмом медианы медианов (Θ (n)). Оба этих алгоритма работают с использованием этапа быстрого сортировки (время O (n)), чтобы переставить элементы и поместить один элемент в правильное положение. Если этот элемент находится в указанном индексе, мы закончили и можем просто вернуть этот элемент. В противном случае мы определяем, с какой стороны следует переписывать и рекурсировать там.
Давайте теперь сделаем очень сильное предположение - предположим, что мы используем quickselect (произвольно выбираем шарнир), и на каждой итерации нам удается угадать точную середину массива. В этом случае наш алгоритм будет работать следующим образом: мы делаем шаг раздела, отбрасываем половину массива, а затем рекурсивно обрабатываем половину массива. Это означает, что при каждом рекурсивном вызове мы заканчиваем работу, пропорциональную длине массива на этом уровне, но эта длина продолжает уменьшаться в два раза на каждой итерации. Если мы выработаем математику (игнорируя постоянные факторы и т.д.), Мы получим следующее время:
- Работа на первом уровне: n
- Работа после одного рекурсивного вызова: n/2
- Работа после двух рекурсивных вызовов: n/4
- Работа после трех рекурсивных вызовов: n/8
- ...
Это означает, что общая работа выполнена
n + n/2 + n/4 + n/8 + n/16 +... = n (1 + 1/2 + 1/4 + 1/8 +...)
Обратите внимание, что этот последний член равен n раз сумме 1, 1/2, 1/4, 1/8 и т.д. Если вы выработаете эту бесконечную сумму, несмотря на то, что существует бесконечно много членов, общая сумма равна 2. Это означает, что общая работа
n + n/2 + n/4 + n/8 + n/16 +... = n (1 + 1/2 + 1/4 + 1/8 +...) = 2n
Это может показаться странным, но идея состоит в том, что если мы выполняем линейную работу на каждом уровне, но продолжаем сокращать массив пополам, мы заканчиваем работу примерно в 2 раза.
Важная деталь здесь состоит в том, что здесь действительно существуют O (log n) разные итерации, но не все из них выполняют равный объем работы. Действительно, каждая итерация выполняет половину работы по сравнению с предыдущей итерацией. Если мы проигнорируем тот факт, что работа уменьшается, вы можете заключить, что работа O (n log n), которая является правильной, но не плотной. Этот более точный анализ, который использует тот факт, что выполненная работа продолжает уменьшаться на каждой итерации, дает время выполнения O (n).
Конечно, это очень оптимистичное предположение - мы почти никогда не получаем раскол 50/50! - но используя более мощную версию этого анализа, вы можете сказать, что если вы можете гарантировать любой сплит с постоянным коэффициентом, общая работа будет только некоторой постоянной кратной n. Если мы выберем абсолютно случайный элемент на каждой итерации (как мы это делаем в quickselect), то при ожидании нам нужно выбрать только два элемента, прежде чем мы получим некоторый элемент поворота в середине 50% массива, что означает, что на ожидание, только два раунда выбирая точку опоры необходимо, прежде чем мы в конечном итоге собирание то, что дает 25/75 раскола. Здесь ожидается ожидаемое время выполнения O (n) для quickselect.
Формальный анализ алгоритма медианы медианов намного сложнее, потому что повторение затруднено и нелегко анализировать. Интуитивно, алгоритм работает, выполняя небольшую работу, чтобы гарантировать хорошую ось. Однако, поскольку есть два разных рекурсивных вызова, анализ, подобный приведенному выше, не будет работать корректно. Вы можете использовать расширенный результат, называемый теоремой Akra-Bazzi, или использовать формальное определение big-O, чтобы явно доказать, что время выполнения O (n). Для более детального анализа ознакомьтесь с "Введение в алгоритмы, третье издание" Корменом, Лейсссоном, Ривестом и Штайн.
Надеюсь это поможет!