Существует несколько различных алгоритмов выбора, от гораздо более простого быстрого выбора (ожидаемый O (n), наихудшего O (n 2 )) до более сложного алгоритма медианы медиан (Θ (п)).Оба этих алгоритма работают, используя шаг разделения быстрой сортировки (время 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
Это может показаться странным, но идеяв том, что если мы выполняем линейную работу на каждом уровне, но продолжаем разрезать массив пополам, мы в конечном итоге делаем примерно 2n работы.
Важная информацияЗдесь нет подробностей, что здесь действительно есть O (log n) разных итераций, но не все выполняют одинаковую работу.Действительно, каждая итерация выполняет вдвое меньше работы, чем предыдущая.Если мы игнорируем тот факт, что работа уменьшается, вы можете сделать вывод, что работа является O (n log n), что является правильным, но не жесткой границей.Этот более точный анализ, использующий тот факт, что проделанная работа продолжает уменьшаться на каждой итерации, дает время выполнения O (n).
Конечно, это очень оптимистичное предположение - мы почти никогда не получаем 50 /50 сплит!- но, используя более мощную версию этого анализа, вы можете сказать, что если вы можете гарантировать любое постоянное деление на множители, общая проделанная работа будет только некоторой постоянной величиной, кратной n.Если мы выберем абсолютно случайный элемент на каждой итерации (как мы делаем в быстром отборе), то в ожидании нам нужно выбрать только два элемента, прежде чем мы в конечном итоге выберем некоторый элемент разворота в середине 50% массива, что означает, что наожидание, только два раунда выбора точки разворота требуются прежде, чем мы закончим тем, что выбираем что-то, что дает 25/75 раскол.Вот откуда берется ожидаемое время выполнения O (n) для быстрого выбора.
Формальный анализ алгоритма медианы медиан намного сложнее, потому что рецидив трудно и не так просто проанализировать.Интуитивно понятно, что алгоритм работает, выполняя небольшой объем работы, чтобы гарантировать выбор хорошей точки разворота.Однако, поскольку сделано два разных рекурсивных вызова, анализ, подобный приведенному выше, не будет работать правильно.Вы можете использовать расширенный результат, называемый теоремой Акра-Бацци , или использовать формальное определение big-O, чтобы явным образом доказать, что время выполнения равно O (n).Для более подробного анализа ознакомьтесь с «Введение в алгоритмы, третье издание» Кормена, Лейссерсона, Ривеста и Стейна.
Надеюсь, это поможет!