Алгоритм выбора
В информатике алгоритм выбора — это алгоритм для нахождения k-го по величине элемента в массиве (такой элемент называется k-й порядковой статистикой). Частными случаями этого алгоритма являются нахождение минимального элемента, максимального элемента и медианы. Существует алгоритм, который гарантированно решает задачу выбора k-го по величине элемента за O(n).
Выбор с помощью сортировки
Задачу выбора можно свести к сортировке. В самом деле, можно упорядочить массив, а затем взять нужный по счету элемент. Это эффективно в том случае, когда выбор нужно делать многократно: тогда можно отсортировать массив за O(n log n) и затем выбирать из него элементы. Однако если выбор нужно произвести однократно, данный алгоритм может оказаться неоправданно долгим.
Линейный алгоритм для нахождения минимума (максимума)
Очевидно, как за линейное время найти минимум (максимум) в данном массиве:
- Изначально присвоить [math]\displaystyle{ min = a[0]; }[/math]
- Для каждого элемента [math]\displaystyle{ a[i] }[/math] выполнить: если [math]\displaystyle{ min \gt a[i] }[/math], присвоить [math]\displaystyle{ min = a[i] }[/math].
Линейный в среднем алгоритм для нахождения k-й порядковой статистики
Существует алгоритм для нахождения k-й порядковой статистики, основанный на алгоритме быстрой сортировки и работающий за O(n) в среднем.
Идея алгоритма заключается в том, что массив разбивается на две части относительно случайно (равновероятно) выбранного элемента — в одну часть попадают элементы, меньшие, чем выбранный, в другую — остальные (эта операция выполняется за [math]\displaystyle{ O(n) }[/math], по её окончанию выбранный элемент находится в позиции [math]\displaystyle{ j }[/math]). Если в первой части оказалось ровно [math]\displaystyle{ k-1 }[/math] элементов ([math]\displaystyle{ j=k }[/math]), то выбранный элемент является искомым, если [math]\displaystyle{ j\gt k }[/math], то алгоритм выполняется рекурсивно для первой части массива, иначе — для второй (в последнем случае для следующей итерации от [math]\displaystyle{ k }[/math] отнимается [math]\displaystyle{ j }[/math]). Рекурсивные вызовы приводят к экспоненциально уменьшающемуся с каждой итерацией размеру обрабатываемого массива, и по этой причине время выполнения алгоритма составляет [math]\displaystyle{ O(n) }[/math].
Алгоритм BFPRT (линейный детерминированный)
BFPRT-Алгоритм позволяет найти k-ю порядковую статистику гарантированно за O(n). Назван в честь своих изобретателей: Manual Blum, Robert W. Floyd, Vaughan R. Pratt, Ronald L. Rivest и Robert Endre Tarjan. Используется при достаточно длинном списке элементов, свыше 800 элементов.
Принцип действия
Ввод: число [math]\displaystyle{ i }[/math], обозначающее [math]\displaystyle{ i }[/math]-й элемент.
- Список делится на подмножества элементов, по 5 элементов в каждом (кроме последнего подмножества). Число элементов в подмножествах может превышать 5 и должно быть в любом случае нечётным. Однако если делить список на подмножества из 3 элементов, время работы не будет линейным.
- Каждое подмножество сортируется с помощью подходящего алгоритма сортировки.
- Пусть [math]\displaystyle{ S }[/math] — множество медиан, образовавшихся в подмножествах после сортировки. Рекурсивно находится медиана в [math]\displaystyle{ S }[/math] — медиана медиан. Назовем её [math]\displaystyle{ s }[/math].
- Результирующая после 3 шага структура, имеет следующую особенность:
- Четверть всех элементов в любом случае имеет ключ [math]\displaystyle{ \lt s }[/math]. (Подмножество множества [math]\displaystyle{ S_1 }[/math])
- Четверть всех элементов в любом случае имеет ключ [math]\displaystyle{ \gt s }[/math]. (Подмножество множества [math]\displaystyle{ S_2 }[/math])
- Результирующая после 3 шага структура, имеет следующую особенность:
- Теперь список разбивается относительно медианы s на 2 подмножества [math]\displaystyle{ S_1 }[/math] и [math]\displaystyle{ S_2 }[/math]. При этом нужно сравнить с s только половину всех элементов, так как две четверти элементов уже отсортированы относительно s. В результате каждое из подмножеств [math]\displaystyle{ S_1 }[/math] и [math]\displaystyle{ S_2 }[/math] содержит максимально 3/4 всех элементов (минимально — 1/4 всех элементов).
- Если:
- [math]\displaystyle{ i = |S_1| + 1 }[/math], то искомый элемент найден — это медиана медиан [math]\displaystyle{ s }[/math]
- [math]\displaystyle{ i \leq |S_1| }[/math], то алгоритм вызывается рекурсивно на множестве [math]\displaystyle{ S_1 }[/math]
- в любом другом случае, алгоритм вызывается рекурсивно на множестве [math]\displaystyle{ S_2 }[/math]