Быстрая сортировка

Материал из Викиконспекты
Перейти к: навигация, поиск

Быстрая сортировка (qsort, сортировка Хоара) - один из самых известных и широко используемых алгоритмов сортировки. Среднее время работы O(n\logn), что является асимптотически оптимальным временем работы для алгоритма, основанного на сравнении. Хотя время работы алгоритма для массива из n элементов в худшем случае может составить Θ(n2), на практике этот алгоритм является одним из самых быстрых. Кроме того, быстрая сортировка не требует дополнительной памяти.

Алгоритм

  • из массива выбирается некоторый опорный элемент a[i].
  • запускается процедура разделения массива, которая перемещает все ключи, меньшие, либо равные a[i], влево от него, а все ключи, большие, либо равные a[i] — вправо.
  • для обоих подмассивов: если в подмассиве более двух элементов, рекурсивно запускаем для него ту же процедуру..

Псевдокод

<wikitex>

Quicksort(A, p, r)
    if p < r
        then q = Partition(A, p, r)
            Quicksort(A, p, q)
            Quicksort(A, q + 1, r)

</wikitex> Для сортировки всего массива необходимо выполнить процедуру Quicksort(A,1,length[A]).

Разбиение массива

Основной шаг алгоритма сортировки — процедура Partition, которая переставляет элементы массива A[p..r] нужным образом: <wikitex>

Partition(A, p, r)
    x = A[p]
    i = p - 1
    j = r + 1
    while true
        do repeat j = j - 1
            until A[j] \le x
            repeat i = i + 1
                until A[i] > x
             if i < j
                 then поменять A[i] и A[j]
                 else return j

</wikitex>


Оптимизация глубины рекурсии до O(logn) в худшем случае

Время работы алгоритма сортировки зависит от того, как разбивается массив на каждом шаге. В случае повторяющихся неудачных разбиений опорным элементом, глубина рекурсии может достичь O(n) а время работы алгоритма O(n2). Этого можно избежать, если в цикле разбивать массив, но рекурсивно вызываться только от части, содержащей меньшее число элементов, а большую часть продолжать разбивать в цикле.

Асимптотика

Худшее время работы

Обозначим худшее время работы за T(n). Получим рекуррентное соотношение

T(n)=max(T(q)+T(nq1))+Θ(n),где 0qn1, так как мы разбиваемся на 2 подзадачи.

Предположим, что T(n)c(n2). Тогда получим

T(n)max(cq2+c(nq1)2)+Θ(n)=cMax(q2+(nq1)2)+Θ(n)

Заметим, что q2+(nq1)2 принимает максимальное значение на концах интервала [0; n-1], что позволяет нам сделать оценку

Max(q2+(nq1)2)(n1)2

Подставим это в наше выражение для T(n)

T(n)cn2c(2n1)+Θ(n)cn2

Таким образом T(n)=O(n2).

Среднее время работы

Лемма:
Пусть Х - полное количество сравнений элементов с опорным за время работы сортировки. Тогда время работы сортировки равно O(nlogn).
Доказательство:

Нам необходимо вычислить полное количество сравнений. Переименуем элементы массива как z1...zn, где zi наименьший по порядку элемент. Также введем множество Zij={zi,zi+1...zj}.

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

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

X=n1i=1nj=i+1Xij, где Xij=1 если произошло сравнение zi и zj и Xij=0, если сравнения не произошло.

Применим к обоим частям равенства операцию вычисления матожидания и воспользовавшись ее линейностью получим

E[X]=E[n1i=1nj=i+1Xij]=n1i=1nj=i+1E[Xij]=n1i=1nj=i+1Pr{zi сравнивается с zj}

Осталось вычислить величину Pr{zi сравнивается с zj} - вероятность того, что zi сравнивается с zj. Поскольку предполагается, что все элементы в массиве различны, то при выборе x в качестве опорного элемента впоследствии не будут сравниваться никакие zi и zj для которых zi<x<zj. С другой стороны, если zi выбран в качестве опорного, то он будет сравниваться с каждым элементом Zij кроме себя самого. Таким образом элементы zi и zj сравниваются тогда и только тогда когда первым в множестве Zij опорным элементом был выбран один из них.

Pr{zi сравнивается с zj}=Pr{ первым опорным элементом был zi или zj}=Pr{ первым опорным элементом был zi}+Pr{ первым опорным элементом был zj}=1ji+1+1ji+1=2ji+1

E[X]=n1i=1nj=i+12ji+1=n1i=1nik=12k+1<n1i=1nik=12k=n1i=1O(logn)=O(nlogn)

Mатожидание времени работы быстрой сортировки будет O(nlogn).

Ссылки

http://ru.wikipedia.org/wiki/Быстрая_сортировка

http://en.wikipedia.org/wiki/Quicksort

Литература

  • Т. Кормен, Ч. Лейзерсон, Р. Ривест: Алгоритмы: построение и анализ глава 7