Поиск k-ой порядковой статистики за линейное время — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(не показано 9 промежуточных версий этого же участника)
Строка 1: Строка 1:
 +
Алгоритм был разработан Мануэлем Блюмом (Manuel Blum), Робертом Флойдом (Robert Floyd), Воганом Рональдом Праттом (Vaughan Ronald Pratt), Роном Ривестом (Ron Rivest), Робертом Тарьяном (Robert Tarjan).
 
==Идея алгоритма==
 
==Идея алгоритма==
Этот алгоритм является модификацией алгоритма [[Поиск k-ой порядковой статистики|поиска k-ой порядковой статистики]]. Важное отличие заключается в том, что время работы алгоритма в наихудшем случае — <tex>O(n)</tex>, где <tex>n</tex> — количество элементов в множестве. Главная идея алгоритма заключается в том, чтобы ''гарантировать'' хорошее разбиение массива. Алгоритм выбирает такой рассекающий элемент, что количество чисел, которые меньше рассекающего элемента, не менее <tex dpi = "170">\frac{3n}{10}</tex>. Элементов же больших опорного элемента, также не менее <tex dpi = "170">\frac{3n}{10}</tex>. Благодаря этому алгоритм работает за линейное время в любом случае.
+
Этот алгоритм является модификацией алгоритма [[Поиск k-ой порядковой статистики|поиска k-ой порядковой статистики]]. Важное отличие заключается в том, что время работы алгоритма в наихудшем случае — <tex>O(n)</tex>, где <tex>n</tex> — количество элементов в множестве. Главная идея алгоритма заключается в том, чтобы ''гарантировать'' хорошее разбиение массива. Алгоритм выбирает такой рассекающий элемент, что количество чисел, которые меньше рассекающего элемента, не менее <tex>\dfrac{3n}{10}</tex>. Элементов же больших опорного элемента, также не менее <tex>\dfrac{3n}{10}</tex>. Благодаря этому алгоритм работает за линейное время в любом случае.
  
 
== Описание алгоритма ==
 
== Описание алгоритма ==
#Все <tex>n</tex> элементов входного массива разбиваются на группы по пять элементов, в последней группе будет <tex>n \bmod 5</tex> элементов. Эта группа может оказаться пустой при <tex>n</tex> кратных <tex>5</tex>.
+
#Все <tex>n</tex> элементов входного массива разбиваются на группы по пять элементов, в последней группе будет <tex>n \bmod 5</tex> элементов. Эта группа может оказаться пустой при <tex>n</tex> кратным <tex>5</tex>.
 
#Сначала сортируется каждая группа, затем из каждой группы выбирается медиана.
 
#Сначала сортируется каждая группа, затем из каждой группы выбирается медиана.
 
#Путем рекурсивного вызова шага определяется медиана <tex>x</tex> из множества медиан (верхняя медиана в случае чётного количества), найденных на втором шаге. Найденный элемент массива <tex>x</tex> используется как рассекающий (за <tex>i</tex> обозначим его индекс).
 
#Путем рекурсивного вызова шага определяется медиана <tex>x</tex> из множества медиан (верхняя медиана в случае чётного количества), найденных на втором шаге. Найденный элемент массива <tex>x</tex> используется как рассекающий (за <tex>i</tex> обозначим его индекс).
Строка 23: Строка 24:
 
[[Файл:поиск2.png| 300px]]
 
[[Файл:поиск2.png| 300px]]
  
На рисунке обозначены закрашенные области, в левом верхнем и в правом нижнем углах. В эти области попали все элементы, которые точно меньше или больше рассекающего элемента, соответственно. В каждой области по <tex> 8 </tex> элементов, всего же в массиве <tex> 25 </tex>, то есть мы получили хорошее (то есть соответствующее нашему утверждению) разбиение массива относительно опорного элемента, так как <tex> 8  > </tex> <tex dpi = "170">\frac{3 \cdot 25}{10}</tex>. Теперь докажем, что алгоритм также хорошо выбирает опорный элемент и в общем случае.
+
На рисунке обозначены закрашенные области, в левом верхнем и в правом нижнем углах. В эти области попали все элементы, которые точно меньше или больше рассекающего элемента, соответственно. В каждой области по <tex> 8 </tex> элементов, всего же в массиве <tex> 25 </tex>, то есть мы получили хорошее (то есть соответствующее нашему утверждению) разбиение массива относительно опорного элемента, так как <tex> 8  > </tex> <tex>\dfrac{3 \cdot 25}{10}</tex>. Теперь докажем, что алгоритм также хорошо выбирает опорный элемент и в общем случае.
  
Cначала определим нижнюю границу для количества элементов, превышающих по величине рассекающий элемент <tex>x</tex>. В общем случае как минимум половина медиан, найденных на втором шаге, больше или равны медианы медиан <tex>x</tex>. Таким образом, как минимум <tex>n / 10</tex> групп содержат по <tex>3</tex> превышающих величину <tex>x</tex>, за исключение группы, в которой меньше <tex>5</tex> элементов и ещё одной группы, содержащей сам элемент <tex>x</tex>. Таким образом получаем, что количество элементов больших  <tex>x</tex>, не менее <tex dpi = "170">\frac{3n}{10}</tex>.
+
Cначала определим нижнюю границу для количества элементов, превышающих по величине рассекающий элемент <tex>x</tex>. В общем случае как минимум половина медиан, найденных на втором шаге, больше или равны медианы медиан <tex>x</tex>. Таким образом, как минимум <tex>\dfrac{n}{10}</tex> групп содержат по <tex>3</tex> превышающих величину <tex>x</tex>, за исключение группы, в которой меньше <tex>5</tex> элементов и ещё одной группы, содержащей сам элемент <tex>x</tex>. Таким образом получаем, что количество элементов больших  <tex>x</tex>, не менее <tex>\dfrac{3n}{10}</tex>.
  
Проведя аналогичные рассуждения для элементов, которые меньше по величине, чем рассекающий элемент <tex>x</tex>, мы получим, что как минимум <tex dpi = "170">\frac{3n}{10}</tex> меньше, чем элемент <tex>x</tex>. Теперь проведем анализ времени работы алгоритма.
+
Проведя аналогичные рассуждения для элементов, которые меньше по величине, чем рассекающий элемент <tex>x</tex>, мы получим, что как минимум <tex>\dfrac{3n}{10}</tex> меньше, чем элемент <tex>x</tex>. Теперь проведем анализ времени работы алгоритма.
  
 
[[Файл:поиск5.png| 300px]]
 
[[Файл:поиск5.png| 300px]]
Строка 34: Строка 35:
 
Пусть <tex>T(n)</tex> — время работы алгоритма для <tex>n</tex> элементов, тогда оно не больше, чем сумма:
 
Пусть <tex>T(n)</tex> — время работы алгоритма для <tex>n</tex> элементов, тогда оно не больше, чем сумма:
 
# времени работы на сортировку групп и разбиение по рассекающему элементу, то есть <tex>Cn</tex>;
 
# времени работы на сортировку групп и разбиение по рассекающему элементу, то есть <tex>Cn</tex>;
# времени работы для поиска медианы медиан, то есть <tex>T(</tex><tex dpi = "170">\frac{n}{5}</tex> <tex>) </tex>;
+
# времени работы для поиска медианы медиан, то есть <tex>T</tex><tex>\left(\dfrac{n}{5}\right)</tex>;
# времени работы для поиска <tex>k</tex>-го элемента в одной из двух частей массива, то есть <tex>T(s)</tex>, где <tex>s</tex> — количество элементов в этой части. Но <tex>s</tex> не превосходит <tex dpi = "170">\frac{7n}{10}</tex>, так как чисел, меньших рассекающего элемента, не менее <tex dpi = "170">\frac{3n}{10}</tex> — это <tex dpi = "170">\frac{n}{10}</tex> медиан, меньших медианы медиан, плюс не менее <tex dpi = "170">\frac{2n}{10}</tex> элементов, меньших этих медиан. С другой стороны, чисел, больших рассекающего элемента, так же не менее <tex dpi = "170">\frac{3n}{10}</tex>, следовательно  <tex> s \leqslant </tex> <tex dpi = "170">\frac{7n}{10}</tex>, то есть в худшем случае <tex> s = </tex> <tex dpi = "170">\frac{7n}{10}</tex>.  
+
# времени работы для поиска <tex>k</tex>-го элемента в одной из двух частей массива, то есть <tex>T(s)</tex>, где <tex>s</tex> — количество элементов в этой части. Но <tex>s</tex> не превосходит <tex>\dfrac{7n}{10}</tex>, так как чисел, меньших рассекающего элемента, не менее <tex>\dfrac{3n}{10}</tex> — это <tex>\dfrac{n}{10}</tex> медиан, меньших медианы медиан, плюс не менее <tex>\dfrac{2n}{10}</tex> элементов, меньших этих медиан. С другой стороны, чисел, больших рассекающего элемента, так же не менее <tex>\dfrac{3n}{10}</tex>, следовательно  <tex> s \leqslant </tex> <tex>\dfrac{7n}{10}</tex>, то есть в худшем случае <tex> s = </tex> <tex>\dfrac{7n}{10}</tex>.  
  
 
Тогда получаем, что   
 
Тогда получаем, что   
<tex>T(n) \leqslant T(</tex><tex dpi = "170">\frac{n}{5}</tex><tex>) + T(</tex><tex dpi = "170">\frac{7n}{10}</tex><tex>) + Cn </tex>
+
<tex>T(n) \leqslant T</tex><tex>\left(\dfrac{n}{5}\right)</tex><tex> + T</tex><tex>\left(\dfrac{7n}{10}\right)</tex><tex> + Cn </tex>
  
 
Покажем, что для всех <tex> n </tex> выполняется неравенство <tex>T(n) \leqslant 10Cn </tex>.
 
Покажем, что для всех <tex> n </tex> выполняется неравенство <tex>T(n) \leqslant 10Cn </tex>.
Строка 44: Строка 45:
 
Докажем по индукции:
 
Докажем по индукции:
 
# Предположим, что наше неравенство <tex>T(n) \leqslant 10Cn </tex> выполняется при малых <tex> n </tex>, для некоторой достаточно большой константы <tex> C </tex>.  
 
# Предположим, что наше неравенство <tex>T(n) \leqslant 10Cn </tex> выполняется при малых <tex> n </tex>, для некоторой достаточно большой константы <tex> C </tex>.  
# Тогда, по предположению индукции, <tex>T(</tex><tex dpi = "170">\frac{n}{5}</tex><tex>) \leqslant 10C </tex><tex dpi = "170">\frac{n}{5}</tex><tex> = 2Cn</tex> и <tex> T(</tex><tex dpi = "170">\frac{7n}{10}</tex><tex>) \leqslant 10C </tex><tex dpi = "170">\frac{7n}{10}</tex><tex> = 7Cn</tex>, тогда
+
# Тогда, по предположению индукции, <tex>T</tex><tex>\left(\dfrac{n}{5}\right)</tex> <tex> \leqslant 10C </tex><tex>\dfrac{n}{5}</tex> <tex> = 2Cn</tex> и <tex> T</tex><tex>\left(\dfrac{7n}{10}\right)</tex> <tex> \leqslant 10C </tex><tex>\dfrac{7n}{10}</tex> <tex> = 7Cn</tex>, тогда
<tex>T(n) \leqslant T(</tex><tex dpi = "170">\frac{n}{5}</tex><tex>) + T(</tex><tex dpi = "170">\frac{7n}{10}</tex><tex>) + Cn = 2Cn + 7Cn + Cn = 10Cn \Rightarrow T(n) \leqslant 10Cn</tex>
+
<tex>T(n) \leqslant T</tex><tex>\left(\dfrac{n}{5}\right)</tex> <tex> + T</tex><tex>\left(\dfrac{7n}{10}\right)</tex> <tex> + Cn = 2Cn + 7Cn + Cn = 10Cn \Rightarrow T(n) \leqslant 10Cn</tex>
  
 
Так как <tex>T(n) \leqslant 10Cn </tex>, то время работы алгоритма <tex>O(n)</tex>
 
Так как <tex>T(n) \leqslant 10Cn </tex>, то время работы алгоритма <tex>O(n)</tex>
  
==Литература==
+
==Источники инфомации==
* Кормен, Т., Лейзерсон, Ч., Ривест, Р., Штайн, К. Алгоритмы: построение и анализ
+
* Кормен, Т., Лейзерсон, Ч., Ривест, Р., Штайн, К. '''Алгоритмы: построение и анализ''' {{---}} Вильямс, 2013. {{---}} 1328 с. {{---}} ISBN 978-5-8459-1794-2
 
+
* [http://en.wikipedia.org/wiki/BFPRT#Linear_general_selection_algorithm_-_Median_of_Medians_algorithm Wikipedia — Selection algorithm]
== Ссылки ==
 
* [http://en.wikipedia.org/wiki/BFPRT#Linear_general_selection_algorithm_-_Median_of_Medians_algorithm Selection algorithm — Wikipedia]
 
  
 
[[Категория: Дискретная математика и алгоритмы]]
 
[[Категория: Дискретная математика и алгоритмы]]
 
[[Категория: Сортировки]]
 
[[Категория: Сортировки]]
[[Категория: Поиск k-ой порядковой статистики]]
+
[[Категория: Другие сортировки]]

Версия 18:52, 5 июня 2015

Алгоритм был разработан Мануэлем Блюмом (Manuel Blum), Робертом Флойдом (Robert Floyd), Воганом Рональдом Праттом (Vaughan Ronald Pratt), Роном Ривестом (Ron Rivest), Робертом Тарьяном (Robert Tarjan).

Идея алгоритма

Этот алгоритм является модификацией алгоритма поиска k-ой порядковой статистики. Важное отличие заключается в том, что время работы алгоритма в наихудшем случае — [math]O(n)[/math], где [math]n[/math] — количество элементов в множестве. Главная идея алгоритма заключается в том, чтобы гарантировать хорошее разбиение массива. Алгоритм выбирает такой рассекающий элемент, что количество чисел, которые меньше рассекающего элемента, не менее [math]\dfrac{3n}{10}[/math]. Элементов же больших опорного элемента, также не менее [math]\dfrac{3n}{10}[/math]. Благодаря этому алгоритм работает за линейное время в любом случае.

Описание алгоритма

  1. Все [math]n[/math] элементов входного массива разбиваются на группы по пять элементов, в последней группе будет [math]n \bmod 5[/math] элементов. Эта группа может оказаться пустой при [math]n[/math] кратным [math]5[/math].
  2. Сначала сортируется каждая группа, затем из каждой группы выбирается медиана.
  3. Путем рекурсивного вызова шага определяется медиана [math]x[/math] из множества медиан (верхняя медиана в случае чётного количества), найденных на втором шаге. Найденный элемент массива [math]x[/math] используется как рассекающий (за [math]i[/math] обозначим его индекс).
  4. Массив делится относительно рассекающего элемента [math]x[/math].
  5. Если [math]i = k[/math], то возвращается значение [math]x[/math]. Иначе запускается рекурсивно поиск элемента в одной из частей массива: [math]k[/math]-ой статистики в левой части при [math]i \gt k[/math] или [math](k - i - 1)[/math]-ой статистики в правой части при [math]i \lt k[/math]

Пример работы алгоритма

Рассмотрим работу алгоритма на массиве из [math] 25 [/math] элементов, обозначенных кружками.

На вход подается массив, разобьем элементы на группы по 5 элементов. Отсортируем элементы каждой группы и выберем медианы. Полученные медианы групп отмечены белыми кружками.

Поиск.png


Рекурсивно вызовемся от медиан групп и получим рассекающий элемент. На рисунке он обозначен белым кружком, внутри которого изображен символ [math] x [/math].


Поиск2.png

На рисунке обозначены закрашенные области, в левом верхнем и в правом нижнем углах. В эти области попали все элементы, которые точно меньше или больше рассекающего элемента, соответственно. В каждой области по [math] 8 [/math] элементов, всего же в массиве [math] 25 [/math], то есть мы получили хорошее (то есть соответствующее нашему утверждению) разбиение массива относительно опорного элемента, так как [math] 8 \gt [/math] [math]\dfrac{3 \cdot 25}{10}[/math]. Теперь докажем, что алгоритм также хорошо выбирает опорный элемент и в общем случае.

Cначала определим нижнюю границу для количества элементов, превышающих по величине рассекающий элемент [math]x[/math]. В общем случае как минимум половина медиан, найденных на втором шаге, больше или равны медианы медиан [math]x[/math]. Таким образом, как минимум [math]\dfrac{n}{10}[/math] групп содержат по [math]3[/math] превышающих величину [math]x[/math], за исключение группы, в которой меньше [math]5[/math] элементов и ещё одной группы, содержащей сам элемент [math]x[/math]. Таким образом получаем, что количество элементов больших [math]x[/math], не менее [math]\dfrac{3n}{10}[/math].

Проведя аналогичные рассуждения для элементов, которые меньше по величине, чем рассекающий элемент [math]x[/math], мы получим, что как минимум [math]\dfrac{3n}{10}[/math] меньше, чем элемент [math]x[/math]. Теперь проведем анализ времени работы алгоритма.

Поиск5.png

Анализ времени работы алгоритма

Пусть [math]T(n)[/math] — время работы алгоритма для [math]n[/math] элементов, тогда оно не больше, чем сумма:

  1. времени работы на сортировку групп и разбиение по рассекающему элементу, то есть [math]Cn[/math];
  2. времени работы для поиска медианы медиан, то есть [math]T[/math][math]\left(\dfrac{n}{5}\right)[/math];
  3. времени работы для поиска [math]k[/math]-го элемента в одной из двух частей массива, то есть [math]T(s)[/math], где [math]s[/math] — количество элементов в этой части. Но [math]s[/math] не превосходит [math]\dfrac{7n}{10}[/math], так как чисел, меньших рассекающего элемента, не менее [math]\dfrac{3n}{10}[/math] — это [math]\dfrac{n}{10}[/math] медиан, меньших медианы медиан, плюс не менее [math]\dfrac{2n}{10}[/math] элементов, меньших этих медиан. С другой стороны, чисел, больших рассекающего элемента, так же не менее [math]\dfrac{3n}{10}[/math], следовательно [math] s \leqslant [/math] [math]\dfrac{7n}{10}[/math], то есть в худшем случае [math] s = [/math] [math]\dfrac{7n}{10}[/math].

Тогда получаем, что [math]T(n) \leqslant T[/math][math]\left(\dfrac{n}{5}\right)[/math][math] + T[/math][math]\left(\dfrac{7n}{10}\right)[/math][math] + Cn [/math]

Покажем, что для всех [math] n [/math] выполняется неравенство [math]T(n) \leqslant 10Cn [/math].

Докажем по индукции:

  1. Предположим, что наше неравенство [math]T(n) \leqslant 10Cn [/math] выполняется при малых [math] n [/math], для некоторой достаточно большой константы [math] C [/math].
  2. Тогда, по предположению индукции, [math]T[/math][math]\left(\dfrac{n}{5}\right)[/math] [math] \leqslant 10C [/math][math]\dfrac{n}{5}[/math] [math] = 2Cn[/math] и [math] T[/math][math]\left(\dfrac{7n}{10}\right)[/math] [math] \leqslant 10C [/math][math]\dfrac{7n}{10}[/math] [math] = 7Cn[/math], тогда

[math]T(n) \leqslant T[/math][math]\left(\dfrac{n}{5}\right)[/math] [math] + T[/math][math]\left(\dfrac{7n}{10}\right)[/math] [math] + Cn = 2Cn + 7Cn + Cn = 10Cn \Rightarrow T(n) \leqslant 10Cn[/math]

Так как [math]T(n) \leqslant 10Cn [/math], то время работы алгоритма [math]O(n)[/math]

Источники инфомации

  • Кормен, Т., Лейзерсон, Ч., Ривест, Р., Штайн, К. Алгоритмы: построение и анализ — Вильямс, 2013. — 1328 с. — ISBN 978-5-8459-1794-2
  • Wikipedia — Selection algorithm