<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=178.178.28.57&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=178.178.28.57&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/178.178.28.57"/>
		<updated>2026-04-22T04:50:49Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%91%D1%8B%D1%81%D1%82%D1%80%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=24059</id>
		<title>Быстрая сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%91%D1%8B%D1%81%D1%82%D1%80%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=24059"/>
				<updated>2012-06-05T14:33:52Z</updated>
		
		<summary type="html">&lt;p&gt;178.178.28.57: /* Среднее время работы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Быстрая сортировка''' (qsort, сортировка Хоара) {{---}} один из самых известных и широко используемых алгоритмов сортировки. Среднее время работы &amp;lt;Tex&amp;gt;O(n\log{n})&amp;lt;/Tex&amp;gt;, что является асимптотически оптимальным временем работы для алгоритма, основанного на сравнении. Хотя время работы алгоритма для массива из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов в худшем случае может составить &amp;lt;tex&amp;gt;\Theta(n^2)&amp;lt;/tex&amp;gt;, на практике этот алгоритм является одним из самых быстрых. Кроме того, быстрая сортировка не требует дополнительной памяти.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
* из массива выбирается некоторый опорный элемент &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* запускается процедура разделения массива, которая перемещает все ключи, меньшие, либо равные &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt;, влево от него, а все ключи, большие, либо равные &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; {{---}} вправо.&lt;br /&gt;
* для обоих подмассивов: если в подмассиве более двух элементов, рекурсивно запускаем для него ту же процедуру..&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
&amp;lt;wikitex&amp;gt;&lt;br /&gt;
 Quicksort(A, p, r)&lt;br /&gt;
     if p &amp;lt; r&lt;br /&gt;
         then q = Partition(A, p, r)&lt;br /&gt;
             Quicksort(A, p, q)&lt;br /&gt;
             Quicksort(A, q + 1, r)&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
Для сортировки всего массива необходимо выполнить процедуру &amp;lt;tex&amp;gt;Quicksort(A, 1, length[A])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Разбиение массива===&lt;br /&gt;
Основной шаг алгоритма сортировки {{---}} процедура &amp;lt;tex&amp;gt;Partition&amp;lt;/tex&amp;gt;, которая переставляет элементы массива &amp;lt;tex&amp;gt;A[p..r]&amp;lt;/tex&amp;gt; нужным образом:&lt;br /&gt;
&amp;lt;wikitex&amp;gt;&lt;br /&gt;
 Partition(A, p, r)&lt;br /&gt;
     x = A[p]&lt;br /&gt;
     i = p - 1&lt;br /&gt;
     j = r + 1&lt;br /&gt;
     while true&lt;br /&gt;
         do repeat j = j - 1&lt;br /&gt;
             until A[j] &amp;lt;tex&amp;gt;\leq&amp;lt;/tex&amp;gt; x&lt;br /&gt;
             repeat i = i + 1&lt;br /&gt;
                 until A[i] &amp;gt; x&lt;br /&gt;
             if i &amp;lt; j&lt;br /&gt;
                 then поменять A[i] и A[j]&lt;br /&gt;
                 else return j&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
===Худшее время работы===&lt;br /&gt;
Предположим, что мы разбиваем массив так, что одна часть содержит &amp;lt;tex&amp;gt;n - 1&amp;lt;/tex&amp;gt; элементов, а вторая {{---}} &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Поскольку процедура разбиения занимает время &amp;lt;tex&amp;gt;\Theta(n)&amp;lt;/tex&amp;gt;, для времени работы &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; получаем соотношение:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n) = T(n - 1) + \Theta(n) = \sum\limits_{k=1}^{n} \Theta(k) = \Theta(\sum\limits_{k=1}^{n} k) = \Theta(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы видим, что при максимально несбалансированном разбиении время работы составляет &amp;lt;tex&amp;gt;\Theta(n^2)&amp;lt;/tex&amp;gt;. В частности, это происходит, если массив изначально отсортирован.&lt;br /&gt;
&lt;br /&gt;
===Среднее время работы===&lt;br /&gt;
{{&lt;br /&gt;
Лемма&lt;br /&gt;
|statement=Пусть Х {{---}} полное количество сравнений элементов с опорным за время работы сортировки. Тогда время работы сортировки равно &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=Нам необходимо вычислить полное количество сравнений.&lt;br /&gt;
Переименуем элементы массива как &amp;lt;tex&amp;gt;z_1...z_n&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; наименьший по порядку элемент.&lt;br /&gt;
Также введем множество &amp;lt;tex&amp;gt;Z_{ij} = \{z_i, z_{i+1}...z_j\}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что сравнеие каждой пары элементов происходит не больше одного раза, так как элемент сравнивается с опорным, а опорный элемент после разбиения больше не будет участвовать в сравнении.&lt;br /&gt;
&lt;br /&gt;
Поскольку каждая пара элементов срановается не более одного раза, полное количество сравнений выражается как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;X = \sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n} X_{ij}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;X_{ij} = 1&amp;lt;/tex&amp;gt; если произошло сравнение &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;  и &amp;lt;tex&amp;gt;X_{ij} = 0&amp;lt;/tex&amp;gt;, если сравнения не произошло.&lt;br /&gt;
&lt;br /&gt;
Применим к обоим частям равенства операцию вычисления матожидания и воспользовавшись ее линейностью получим&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;E[X] = E\left[\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n} X_{ij}\right] = \sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n} E[X_{ij}] = \sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n} Pr\{z_i&amp;lt;/tex&amp;gt; сравнивается с &amp;lt;tex&amp;gt;z_j\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Осталось вычислить величину &amp;lt;tex&amp;gt;Pr\{z_i&amp;lt;/tex&amp;gt; сравнивается с &amp;lt;tex&amp;gt;z_j\}&amp;lt;/tex&amp;gt; {{---}} вероятность того, что &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; сравнивается с &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;. Поскольку предполагается, что все элементы в массиве различны, то при выборе &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; в качестве опорного элемента впоследствии не будут сравниваться никакие &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; для которых &amp;lt;tex&amp;gt;z_i &amp;lt; x &amp;lt; z_j&amp;lt;/tex&amp;gt;. С другой стороны, если &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; выбран в качестве опорного, то он будет сравниваться с каждым элементом &amp;lt;tex&amp;gt;Z_{ij}&amp;lt;/tex&amp;gt; кроме себя самого. Таким образом элементы &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; сравниваются тогда и только тогда когда первым в множестве &amp;lt;tex&amp;gt;Z_{ij}&amp;lt;/tex&amp;gt; опорным элементом был выбран один из них.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;Pr\{z_i&amp;lt;/tex&amp;gt; сравнивается с &amp;lt;tex&amp;gt;z_j\} = &lt;br /&gt;
Pr\{&amp;lt;/tex&amp;gt;первым опорным элементом был &amp;lt;tex&amp;gt;z_i&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;z_j\} = &lt;br /&gt;
Pr\{&amp;lt;/tex&amp;gt;первым опорным элементом был &amp;lt;tex&amp;gt;z_i\} +&lt;br /&gt;
Pr\{&amp;lt;/tex&amp;gt;первым опорным элементом был &amp;lt;tex&amp;gt;z_j\} =&lt;br /&gt;
\frac {1}{j-i+1} + \frac {1}{j-i+1}  = \frac {2}{j-i+1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; E[X] = \sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n} \frac {2}{j-i+1} = \sum\limits_{i=1}^{n-1}\sum\limits_{k=1}^{n-i} \frac 2{k+1} &amp;lt; \sum\limits_{i=1}^{n-1}\sum\limits_{k=1}^{n-i} \frac 2{k} = \sum\limits_{i=1}^{n-1}O(\log n) = O(n \log n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Mатожидание времени работы быстрой сортировки будет &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Способы разбиения массива==&lt;br /&gt;
* При выборе опорного элемента из данного диапазона случайным образом худший случай становится очень маловероятным и ожидаемое время выполнения алгоритма сортировки — O(''n''&amp;amp;nbsp;lg&amp;amp;nbsp;''n'').&lt;br /&gt;
* Выбирать опорным элементом средний из трех (первого, среднего и последнего элементов). Такой выбор также направлен против худшего случая.&lt;br /&gt;
* Разбивать массив не на две, а на три части.&lt;br /&gt;
&lt;br /&gt;
==Оптимизация глубины рекурсии до O(logn) в худшем случае==&lt;br /&gt;
Время работы алгоритма сортировки зависит от того, как разбивается массив на каждом шаге. В случае повторяющихся неудачных разбиений опорным элементом, глубина рекурсии может достичь &amp;lt;Tex&amp;gt;O(n)&amp;lt;/Tex&amp;gt; а время работы алгоритма &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Этого можно избежать, если в цикле разбивать массив, но рекурсивно вызываться только от части, содержащей меньшее число элементов, а большую часть продолжать разбивать в цикле.&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* http://ru.wikipedia.org/wiki/Быстрая_сортировка&lt;br /&gt;
 &lt;br /&gt;
* http://en.wikipedia.org/wiki/Quicksort&lt;br /&gt;
&lt;br /&gt;
==Литература==&lt;br /&gt;
* Т. Кормен, Ч. Лейзерсон, Р. Ривест: Алгоритмы: построение и анализ глава 7&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>178.178.28.57</name></author>	</entry>

	</feed>