Поиск k-ой порядковой статистики — различия между версиями
(Новая страница: «{{В разработке}} {{Определение |definition= '''<tex>k</tex>-ой порядковой статистикой''' набора элементо…») |
м (rollbackEdits.php mass rollback) |
||
| (не показано 9 промежуточных версий 7 участников) | |||
| Строка 1: | Строка 1: | ||
| − | |||
| − | |||
{{Определение | {{Определение | ||
|definition= | |definition= | ||
| Строка 9: | Строка 7: | ||
=== Описание алгоритма === | === Описание алгоритма === | ||
| − | Будем использовать процедуру рассечения массива элементов из алгоритма сортировки QuickSort. Пусть нам надо найти <tex>k</tex>-ую порядковую статистику, а после рассечения опорный элемент встал на позицию <tex>m</tex>. Возможно три случая: | + | Будем использовать процедуру рассечения массива элементов из алгоритма сортировки [[Быстрая сортировка|QuickSort]]. Пусть нам надо найти <tex>k</tex>-ую порядковую статистику, а после рассечения опорный элемент встал на позицию <tex>m</tex>. Возможно три случая: |
* '''k = m'''. Порядковая статистика найдена. | * '''k = m'''. Порядковая статистика найдена. | ||
| − | * '''k < m'''. Рекурсивно ищем <tex>k</tex>-ую статистику в первой | + | * '''k < m'''. Рекурсивно ищем <tex>k</tex>-ую статистику в первой части массива. |
| − | * '''k > m'''. Рекурсивно ищем <tex>(k - m - 1)</tex>-ую статистику во второй | + | * '''k > m'''. Рекурсивно ищем <tex>(k - m - 1)</tex>-ую статистику во второй части массива. |
=== Код алгоритма === | === Код алгоритма === | ||
| − | Ниже представлен код представленного алгоритма. При реализации, однако, вместо рекурсивных вызовов изменяются границы поиска статистики во внешнем цикле. В коде | + | Ниже представлен код представленного алгоритма. При реализации, однако, вместо рекурсивных вызовов изменяются границы поиска статистики во внешнем цикле. В коде считаем, что процедура '''partition''' принимает массив и границы отрезка, который будет рассечён (причём правая граница отрезка не включается), и возвращает индекс опорного элемента. Также считается, что массив индексируется с нуля. |
| − | int findOrderStatistic(int[] array, int k) { | + | '''int''' findOrderStatistic('''int[]''' array, '''int''' k) { |
| − | int left = 0, right = array.length; | + | '''int''' left = 0, right = array.length; |
| − | while (true) { | + | '''while''' ('''true''') { |
| − | int mid = partition(array, left, right); | + | '''int''' mid = partition(array, left, right); |
| − | if (mid == k) { | + | '''if''' (mid == k) { |
| − | return array[mid]; | + | '''return''' array[mid]; |
} | } | ||
| − | else if (k < mid) { | + | '''else if''' (k < mid) { |
right = mid; | right = mid; | ||
} | } | ||
| − | else { | + | '''else''' { |
| − | |||
left = mid + 1; | left = mid + 1; | ||
} | } | ||
| Строка 39: | Строка 36: | ||
=== Анализ времени работы === | === Анализ времени работы === | ||
| − | Аналогично QuickSort, может возникнуть такой же | + | Аналогично QuickSort, может возникнуть такой же худший случай (процедура '''partition''' возвращает каждый раз левую или правую границу рассматриваемой части), при котором время работы составит <tex>\Omega(n^2)</tex>. Однако, если считать, что '''partition''' возвращает все элементы рассматриваемого отрезка с равной вероятностью, то можно оценить матожидание времени работы как <tex>O(n)</tex>. |
| + | |||
| + | Будем оценивать количество сравнений. При поиске статистики в массиве размера <tex>n</tex> функция '''partition''' (точнее, одна из распространённых вариаций) совершает не более <tex>n - 1</tex> сравнений. Далее, в зависимости от <tex>k</tex> выбирается левая или правая половины (или вообще алгоритм завершает работу). Оценку проводим сверху, то есть, будем считать, что каждый раз выбирается большая половина. | ||
| + | |||
| + | :<tex>T(n) \le \frac 1n \sum\limits_{k = 1}^n \left ( T \left ( \max \left \{k - 1; n - k \right \} \right ) + n - 1 \right ) =</tex> | ||
| + | :<tex>= n - 1 + \frac 1n \sum\limits_{k = 1}^n T(\max \{k - 1; n - k\}) = n - 1 + \frac 2n \sum\limits_{k = \lfloor n/2 \rfloor}^{n - 1} T(k)</tex> | ||
| + | |||
| + | Предположим, что <tex>T(k) \le ck</tex> для некоторой константы <tex>c</tex> и всех <tex>k < n</tex> (будем доказывать оценку по индукции). Тогда верно неравенство: | ||
| + | |||
| + | :<tex>T(n) = n - 1 + \frac 2n \sum\limits_{k = \lfloor n/2 \rfloor}^{n - 1} ck</tex> | ||
| + | |||
| + | Преобразуем сумму из правой части равенства по формуле суммы арифметической прогрессии и оценим преобразованное выражение: | ||
| + | |||
| + | :<tex>\sum\limits_{k = \lfloor n/2 \rfloor}^{n - 1} ck = \frac 12 \left (\left \lceil \frac n2 \right \rceil - 1 \right) \left( c \left \lfloor \frac n2 \right \rfloor + c(n - 1) \right ) \le \frac c2 \left (\frac{n + 1}2 - 1\right) \frac{3n - 2}2 = c \frac{n - 1}4 \frac{3n - 2}2</tex> | ||
| + | |||
| + | Воспользуемся полученной оценкой для оценки исходного выражения. Также, предположим, что <tex>c \ge 4</tex>: | ||
| + | |||
| + | :<tex>T(n) \le n - 1 + \frac{2c}n \frac{n - 1}4 \frac{3n - 2}2 = n - 1 + c\frac{n - 1}{2n} \frac{3n - 2}2 \le \frac c4 (n - 1) + \frac c4\left (\frac{n - 1}n (3n - 2)\right) \le</tex> | ||
| + | :<tex>\le \frac c4 (n - 1 + 3n - 2) = \frac c4 (4n - 3) \le cn</tex> | ||
| + | |||
| + | Для довершения доказательства необходима проверка базы индукции, но она тривиальна: для выборки порядковой статистики из одного элемента сравнений не требуется: <tex>T(1) = 0 < 4</tex>. Итого, мы доказали, что <tex>T(n) \le 4n</tex>, следовательно, <tex>T(n) = O(n)</tex> | ||
| + | |||
| + | == Ссылки == | ||
| + | * [http://en.wikipedia.org/wiki/BFPRT Selection algorithm — Wikipedia] | ||
| + | * Donald Knuth. The Art of Computer Programming, Volume 3: Sorting and Searching, Third Edition. Addison-Wesley, 1997. ISBN 0-201-89685-0. Section 5.3.3: Minimum-Comparison Selection, pp.207–219. | ||
Текущая версия на 19:43, 4 сентября 2022
| Определение: |
| -ой порядковой статистикой набора элементов линейно упорядоченного множества называется такой его элемент, который является -ым элементом набора в порядке сортировки |
Содержание
Модификация QuickSort
Описание алгоритма
Будем использовать процедуру рассечения массива элементов из алгоритма сортировки QuickSort. Пусть нам надо найти -ую порядковую статистику, а после рассечения опорный элемент встал на позицию . Возможно три случая:
- k = m. Порядковая статистика найдена.
- k < m. Рекурсивно ищем -ую статистику в первой части массива.
- k > m. Рекурсивно ищем -ую статистику во второй части массива.
Код алгоритма
Ниже представлен код представленного алгоритма. При реализации, однако, вместо рекурсивных вызовов изменяются границы поиска статистики во внешнем цикле. В коде считаем, что процедура partition принимает массив и границы отрезка, который будет рассечён (причём правая граница отрезка не включается), и возвращает индекс опорного элемента. Также считается, что массив индексируется с нуля.
int findOrderStatistic(int[] array, int k) {
int left = 0, right = array.length;
while (true) {
int mid = partition(array, left, right);
if (mid == k) {
return array[mid];
}
else if (k < mid) {
right = mid;
}
else {
left = mid + 1;
}
}
}
Анализ времени работы
Аналогично QuickSort, может возникнуть такой же худший случай (процедура partition возвращает каждый раз левую или правую границу рассматриваемой части), при котором время работы составит . Однако, если считать, что partition возвращает все элементы рассматриваемого отрезка с равной вероятностью, то можно оценить матожидание времени работы как .
Будем оценивать количество сравнений. При поиске статистики в массиве размера функция partition (точнее, одна из распространённых вариаций) совершает не более сравнений. Далее, в зависимости от выбирается левая или правая половины (или вообще алгоритм завершает работу). Оценку проводим сверху, то есть, будем считать, что каждый раз выбирается большая половина.
Предположим, что для некоторой константы и всех (будем доказывать оценку по индукции). Тогда верно неравенство:
Преобразуем сумму из правой части равенства по формуле суммы арифметической прогрессии и оценим преобразованное выражение:
Воспользуемся полученной оценкой для оценки исходного выражения. Также, предположим, что :
Для довершения доказательства необходима проверка базы индукции, но она тривиальна: для выборки порядковой статистики из одного элемента сравнений не требуется: . Итого, мы доказали, что , следовательно,
Ссылки
- Selection algorithm — Wikipedia
- Donald Knuth. The Art of Computer Programming, Volume 3: Sorting and Searching, Third Edition. Addison-Wesley, 1997. ISBN 0-201-89685-0. Section 5.3.3: Minimum-Comparison Selection, pp.207–219.