К содержимому
ИС30

Поиск по сайту

Конспекты, лабы, квизы, ЧаВо и страницы

Войти
Алгоритмы и структуры данныхПрактика25 сентября 2026 г.

Практика 25 сентября. Мастер-теорема, быстрая сортировка, нижняя оценка сортировок

Мастер-теорема через дерево рекурсии и три случая, быстрая сортировка, разбиения Хоара и Ломуто и их отличие, выбор опорного, асимптотика и память, неустойчивость, нижняя оценка n log n для сортировок сравнением, компараторы.

Практика после лекций про сортировку слиянием и быструю сортировку. Сначала — мастер-теорема: как по рекуррентному соотношению сразу получить асимптотику рекурсивного алгоритма и почему у слияния выходит nlog⁡nn\log n. Потом подробный разбор быстрой сортировки: два способа разбиения, выбор опорного элемента, время и память. Разбиения Хоара и Ломуто на тестах и коллоквиумах путают особенно часто. В конце доказано, что никакая сортировка сравнениями не работает в худшем случае быстрее nlog⁡nn\log n.

Самая частая ошибка на тестах

«В Хоаре опорный элемент — средний, в Ломуто — последний» — неверно. Опорный элемент можно выбрать как угодно в обеих схемах, выбор не связан со способом разбиения. Схемы отличаются только тем, как работают указатели (§2.4).

1. Мастер-теорема

1.1. Рекуррентное соотношение

Алгоритм «разделяй и властвуй» делит задачу размера nn на части, рекурсивно решает некоторые из них и что-то делает сам. Время его работы описывается соотношением T(n)=a⋅T ⁣(nb)+f(n).T(n)=a\cdot T\!\left(\frac nb\right)+f(n).

ПараметрСмысл
aaсколько рекурсивных вызовов делается из одного вызова
bbво сколько раз уменьшается размер задачи в вызове
f(n)f(n)«полезная работа» самого вызова без рекурсии: разделить данные, собрать ответ

Обычно f(n)f(n) — многочлен, и оценивают его старшей степенью: f(n)=Θ(nc)f(n)=\Theta(n^c). Если ff не многочлен, её ограничивают подходящим многочленом; есть и общая версия теоремы, до неё курс дойдёт позже.

Алгоритмaabbf(n)f(n)cc
Сортировка слиянием2222слияние двух половин, Θ(n)\Theta(n)11
Бинарный поиск1122одно сравнение, Θ(1)\Theta(1)00

В слиянии обе половины сортируются рекурсивно, поэтому a=2a=2. В бинарном поиске массив тоже делится пополам, но дальше работаем только с одной половиной — a=1a=1. Параметр bb показывает, какая часть массива приходится на один вызов: в обоих случаях половина, b=2b=2.

1.2. Дерево рекурсии

Нарисуем вызовы деревом. Корень — задача размера nn, у каждого узла aa детей размера в bb раз меньше.

УровеньУзловРазмер задачиРабота на уровне
0011nnncn^c
11aanb\frac nba(nb)c=nc⋅abca\left(\frac nb\right)^c=n^c\cdot\frac a{b^c}
iiaia^inbi\frac n{b^i}ai(nbi)c=nc(abc)ia^i\left(\frac n{b^i}\right)^c=n^c\left(\frac a{b^c}\right)^i
log⁡bn\log_bnalog⁡bna^{\log_bn}11nc(abc)log⁡bnn^c\left(\frac a{b^c}\right)^{\log_bn}

Размер уменьшается в bb раз, пока не станет 11, поэтому уровней log⁡bn+1\log_bn+1. Складываем работу по уровням: T(n)=nc∑i=0log⁡bnqi,q=abc.T(n)=n^c\sum_{i=0}^{\log_bn}q^i,\qquad q=\frac a{b^c}. Это геометрическая прогрессия, и ответ зависит только от того, сравнима ли qq с единицей.

1.3. Три случая

q=1q=1, то есть a=bca=b^c. На каждом уровне делается одинаковая работа ncn^c — от числа уровней она не зависит. Сумма — это log⁡bn+1\log_bn+1 единиц: T(n)=Θ(nclog⁡n).T(n)=\Theta(n^c\log n). Основание логарифма не пишут: log⁡bn=log⁡2nlog⁡2b\log_bn=\frac{\log_2n}{\log_2b}, логарифмы по разным основаниям отличаются в константу раз.

q<1q<1, то есть a<bca<b^c. Работа убывает от корня к листьям, и самый «жирный» уровень — корень. Сумма ограничена константой: ∑i≥0qi=11−q,T(n)=Θ(nc).\sum_{i\ge0}q^i=\frac1{1-q},\qquad T(n)=\Theta(n^c). Даже если q=0,999q=0{,}999, сумма не больше 10001000 — огромная, но константа, и асимптотику она не меняет.

q>1q>1, то есть a>bca>b^c. Работа растёт к листьям, самый тяжёлый уровень — нижний, и сумма с точностью до константы равна последнему слагаемому: nc qlog⁡bn=nc⋅alog⁡bn(blog⁡bn)c=nc⋅alog⁡bnnc=alog⁡bn=nlog⁡ba.n^c\,q^{\log_bn}=n^c\cdot\frac{a^{\log_bn}}{\left(b^{\log_bn}\right)^c}=n^c\cdot\frac{a^{\log_bn}}{n^c}=a^{\log_bn}=n^{\log_ba}. Последнее равенство — логарифмирование: log⁡b(alog⁡bn)=log⁡bn⋅log⁡ba=log⁡b(nlog⁡ba)\log_b\big(a^{\log_bn}\big)=\log_bn\cdot\log_ba=\log_b\big(n^{\log_ba}\big). Итак, T(n)=Θ(nlog⁡ba)T(n)=\Theta(n^{\log_ba}).

УсловиеГде основная работаT(n)T(n)
a<bca<b^cв корнеΘ(nc)\Theta(n^c)
a=bca=b^cпоровну на всех уровняхΘ(nclog⁡n)\Theta(n^c\log n)
a>bca>b^cв листьяхΘ(nlog⁡ba)\Theta(n^{\log_ba})

То же самое удобно помнить как сравнение cc с log⁡ba\log_ba: какое из двух чисел больше, та степень и побеждает, а при равенстве добавляется логарифм.

Примеры.

  • Слияние: a=2a=2, bc=21=2b^c=2^1=2 — случай a=bca=b^c, T(n)=Θ(nlog⁡n)T(n)=\Theta(n\log n).
  • Бинарный поиск: a=1=20a=1=2^0 — тоже равенство, T(n)=Θ(n0log⁡n)=Θ(log⁡n)T(n)=\Theta(n^0\log n)=\Theta(\log n).
  • T(n)=T(n2)+nT(n)=T\big(\frac n2\big)+n: a=1<2a=1<2 — работа в корне, n+n2+n4+⋯<2nn+\frac n2+\frac n4+\dots<2n, T(n)=Θ(n)T(n)=\Theta(n).
  • T(n)=4T(n2)+nT(n)=4T\big(\frac n2\big)+n: a=4>2a=4>2 — работа в листьях, T(n)=Θ(nlog⁡24)=Θ(n2)T(n)=\Theta(n^{\log_24})=\Theta(n^2). Третий случай может давать и n2n^2, и n3n^3, и дробные степени: при a=3a=3, b=2b=2, c=1c=1 получается nlog⁡23≈n1,585n^{\log_23}\approx n^{1{,}585}.
Что нужно знать на коллоквиуме

Вывод теоремы строгий: если скажут «докажите, я не верю» — вот он. Но на коллоквиуме достаточно сказать, что асимптотика слияния nlog⁡nn\log n получается по мастер-теореме, и объяснить, что это случай a=bca=b^c. Кто сможет вывести три случая, как выше, — только выиграет.

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

2.1. Идея: работа на спуске

В сортировке слиянием работа делается на подъёме рекурсии: массив делится пополам без всякой работы, а сливаются уже отсортированные половины.

В быстрой сортировке наоборот, работа делается на спуске. Выбирается опорный элемент pp, и массив разбивается так, чтобы слева оказались элементы ≤p\le p, а справа — элементы ≥p\ge p. Затем каждая часть сортируется рекурсивно. На подъёме делать ничего не нужно: части уже стоят в правильном порядке относительно друг друга.

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

2.2. Разбиение Хоара

Два равноправных указателя идут навстречу друг другу с двух концов:

  • ii идёт слева направо и останавливается на элементе ≥p\ge p — он «не на своей половине»;
  • jj идёт справа налево и останавливается на элементе ≤p\le p;
  • если i≤ji\le j, элементы меняются местами, и оба указателя сдвигаются дальше;
  • так продолжается, пока указатели не пересекутся.

После этого элементы с индексами от начала до jj не больше pp, а от ii до конца — не меньше pp.

Пример. Массив 7,1,8,3,5,4,9,2,67,1,8,3,5,4,9,2,6, опорный p=5p=5 (взят из середины — только для наглядности).

Шагii стопjj стопОбменМассив после
1a0=7a_0=7a7=2a_7=2 (пропустили 66)7↔27\leftrightarrow22,1,8,3,5,4,9,7,62,1,8,3,5,4,9,7,6
2a2=8a_2=8 (пропустили 11)a5=4a_5=4 (пропустили 99)8↔48\leftrightarrow42,1,4,3,5,8,9,7,62,1,4,3,5,8,9,7,6
3a4=5a_4=5 (пропустили 33)a4=5a_4=55↔55\leftrightarrow5без изменений

Теперь i=5i=5, j=3j=3 — указатели пересеклись. Слева 2,1,4,3≤52,1,4,3\le5, справа 8,9,7,6≥58,9,7,6\ge5, и рекурсия запускается от [0;3][0;3] и [5;8][5;8].

quick_sort_hoare.cpp
void quick_sort(vector<int>& a, int l, int r) {
    if (l >= r) return;
    int p = a[l + rand() % (r - l + 1)];  // опорный — любой, здесь случайный
    int i = l, j = r;
    while (i <= j) {
        while (a[i] < p) i++;   // стоп на элементе >= p
        while (a[j] > p) j--;   // стоп на элементе <= p
        if (i <= j) swap(a[i++], a[j--]);
    }
    quick_sort(a, l, j);        // a[l..j] <= p
    quick_sort(a, i, r);        // a[i..r] >= p
}

2.3. Разбиение Ломуто

Указатели неравноправны и идут в одну сторону:

  • ii — граница: всё левее ii меньше опорного;
  • jj просто проходит по массиву;
  • если aj<pa_j<p, то aja_j меняется с aia_i, и граница ii сдвигается вправо.

В классической записи опорный сначала переставляют в конец, а после прохода ставят на место ii — на границу между частями.

Пример. Тот же массив и тот же опорный 55. Переставляем 55 в конец: 7,1,8,3,6,4,9,2,5‾7,1,8,3,6,4,9,2,\underline5, i=0i=0.

jjaja_jaj<5a_j<5?ДействиеМассив после
07нет—7,1,8,3,6,4,9,2,57,1,8,3,6,4,9,2,5
11даa0↔a1a_0\leftrightarrow a_1, i=1i=11,7,8,3,6,4,9,2,51,7,8,3,6,4,9,2,5
28нет—
33даa1↔a3a_1\leftrightarrow a_3, i=2i=21,3,8,7,6,4,9,2,51,3,8,7,6,4,9,2,5
46нет—
54даa2↔a5a_2\leftrightarrow a_5, i=3i=31,3,4,7,6,8,9,2,51,3,4,7,6,8,9,2,5
69нет—
72даa3↔a7a_3\leftrightarrow a_7, i=4i=41,3,4,2,6,8,9,7,51,3,4,2,6,8,9,7,5

В конце меняем a4a_4 с опорным: 1,3,4,2,5,8,9,7,61,3,4,2,\mathbf5,8,9,7,6. Пятёрка стоит на индексе 44 — ровно там же, где в отсортированном массиве 1,2,…,91,2,\dots,9.

quick_sort_lomuto.cpp
void quick_sort(vector<int>& a, int l, int r) {
    if (l >= r) return;
    swap(a[l + rand() % (r - l + 1)], a[r]);  // опорный — в конец
    int p = a[r];
    int i = l;                                // a[l..i-1] < p
    for (int j = l; j < r; j++)
        if (a[j] < p) swap(a[i++], a[j]);
    swap(a[i], a[r]);                         // опорный на своё место
    quick_sort(a, l, i - 1);
    quick_sort(a, i + 1, r);
}

Студенты, сравнивавшие обе схемы бенчмарками, иногда получают, что Ломуто быстрее, хотя классически быстрее считается Хоар. Преподаватель посоветовал статью на Хабре о том, как Ломуто можно оптимизировать под современные процессоры, — в том числе поэтому его и изучают.

2.4. Чем отличаются Хоар и Ломуто

Вопрос «в чём разница между разбиениями Хоара и Ломуто» любят задавать на тестах и коллоквиуме: ответ короткий и сразу показывает, понимаете ли вы тему. Правильный ответ:

  • разница только в принципе разбиения;
  • в Хоаре два равноправных указателя идут с разных сторон и меняют местами элементы, стоящие не в своей половине;
  • в Ломуто один указатель отвечает за границу элементов меньше опорного, другой проходит по массиву.

Следствие: в Ломуто опорный элемент после разбиения стоит на своём окончательном месте и в рекурсию больше не попадает. В Хоаре это не гарантировано: опорный может остаться внутри одной из частей и переехать позже.

Чего не говорить

«В Хоаре берём средний опорный, в Ломуто — последний». Это только привычка из учебных примеров: середина удобна на рисунке. В коде выше в обеих схемах опорный случайный, и обе корректны. Каждый год примерно половина людей отвечает на тесте именно так — и теряет балл.

2.5. Время работы

Лучший случай — разбиение каждый раз пополам. Это то же дерево, что у слияния: T(n)=2T(n2)+Θ(n)=Θ(nlog⁡n)T(n)=2T\big(\frac n2\big)+\Theta(n)=\Theta(n\log n).

Средний случай — тоже Θ(nlog⁡n)\Theta(n\log n), даже если разбиение неровное. Пусть массив каждый раз делится в отношении 110:910\frac1{10}:\frac9{10}. Самая длинная ветвь — та, где каждый раз отрезается лишь десятая часть. Её глубина log⁡10/9n\log_{10/9}n, то есть снова логарифм, только по другому основанию, а основание — константа. На каждом уровне в сумме обрабатывается не больше nn элементов, поэтому время O(nlog⁡n)O(n\log n).

Худший случай — опорным каждый раз оказывается минимум или максимум. Тогда массив делится на 11 и n−1n-1, потом на 11 и n−2n-2, и так далее: глубина рекурсии nn, а работа n+(n−1)+(n−2)+⋯+1=n(n+1)2=Θ(n2).n+(n-1)+(n-2)+\dots+1=\frac{n(n+1)}2=\Theta(n^2).

2.6. Выбор опорного элемента

СпособКакПроблема
Серединаa[l+r2]a\big[\frac{l+r}2\big]легко построить тест, где в середине всегда минимум или максимум, — и получить n2n^2
Медиана из трёхсредний по величине из первого, среднего и последнеголучше, но против неё тоже строят «плохие» тесты
Случайныйиндекс, случайный в пределах [l;r][l;r]подобрать тест, где случайный элемент всегда крайний, практически нельзя

Медиана из трёх: для массива, где первый элемент 44, средний 55, последний 99, опорным станет 55. Он гарантированно не минимум и не максимум массива, если только все три не равны.

Случайный опорный работает быстро: генератор псевдослучайных чисел выдаёт число за константное время. Настоящей случайности в компьютере нет, но для сортировки это неважно: чтобы опорный всё время оказывался крайним, должно очень сильно не повезти.

Много равных элементов

В Ломуто с условием aj<pa_j<p все элементы, равные опорному, уходят вправо. На массиве из одинаковых чисел каждое разбиение даёт части 00 и n−1n-1, и сортировка деградирует до n2n^2 при любом выборе опорного. Хоар в этом случае меняет равные элементы местами и делит массив примерно пополам.

2.7. Память и устойчивость

СлияниеБыстрая сортировка
Время, худший случайΘ(nlog⁡n)\Theta(n\log n)Θ(n2)\Theta(n^2)
Время, средний случайΘ(nlog⁡n)\Theta(n\log n)Θ(nlog⁡n)\Theta(n\log n)
Доп. памятьO(n)O(n) — буфер для слияниястек рекурсии: O(log⁡n)O(\log n) при разбиении примерно пополам, O(n)O(n) в худшем случае
Устойчивостьустойчиванеустойчива

Память. Быстрой сортировке не нужен буфер: всё переставляется на месте, а на подъёме нечего сливать. Память уходит только на стек рекурсии, и её объём — это глубина рекурсии. У слияния стек тоже есть, но O(log⁡n)O(\log n) несопоставимо меньше буфера на nn элементов, поэтому память слияния — O(n)O(n).

Устойчивость. Сортировка устойчива, если элементы с равными ключами сохраняют исходный порядок. Быстрая сортировка неустойчива: обмены переносят элементы через большие расстояния, и равные элементы могут поменяться местами. На каком-то конкретном массиве порядок равных может и сохраниться, но это не гарантировано — а устойчивость означает именно гарантию.

3. Нижняя оценка сортировок сравнением

3.1. Дерево решений

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

Дерево решений.

  • Узел — состояние алгоритма: текущий порядок элементов и все его переменные.
  • В каждом узле алгоритм задаёт вопрос «ai<aja_i<a_j?». В зависимости от ответа «вселенная расщепляется» на две ветки, и алгоритм переходит в одно из двух новых состояний.
  • Лист — конец работы: алгоритм выдал ответ, то есть перестановку исходного массива, которая делает его отсортированным.

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

3.2. Высота не меньше логарифма факториала

Каждая из n!n! перестановок входного массива требует своего ответа, поэтому листьев не меньше n!n!. У двоичного дерева высоты hh не больше 2h2^h листьев: самое низкое дерево — полное, где на каждом следующем уровне вдвое больше узлов. Значит, 2h≥n!⇒h≥log⁡2n!.2^h\ge n!\quad\Rightarrow\quad h\ge\log_2n!.

Оценим log⁡2n!\log_2n! с двух сторон.

  • Сверху: n!=1⋅2⋯n≤n⋅n⋯n=nnn!=1\cdot2\cdots n\le n\cdot n\cdots n=n^n, поэтому log⁡2n!≤nlog⁡2n\log_2n!\le n\log_2n.
  • Снизу: в произведении 1⋅2⋯n1\cdot2\cdots n последние n2\frac n2 множителей не меньше n2\frac n2, а остальные не меньше 11, поэтому n!≥(n2)n/2n!\ge\left(\frac n2\right)^{n/2} и log⁡2n!≥n2log⁡2n2=n2(log⁡2n−1).\log_2n!\ge\frac n2\log_2\frac n2=\frac n2\big(\log_2n-1\big).

Обе оценки — это nlog⁡nn\log n с точностью до константы, значит, log⁡2n!=Θ(nlog⁡n)\log_2n!=\Theta(n\log n).

Теорема. Любая сортировка сравнением в худшем случае делает Ω(nlog⁡n)\Omega(n\log n) сравнений.

Поэтому сортировка слиянием асимптотически оптимальна среди сортировок сравнением, и никакая хитрость не даст, например, O(nlog⁡log⁡n)O(n\log\log n) в худшем случае.

Числа: n=10n=10 — перестановок 10!=3 628 80010!=3\,628\,800, log⁡210!≈21,8\log_2 10!\approx21{,}8. Любой алгоритм сравнения на каком-то входе из 1010 элементов делает не меньше 2222 сравнений.

Лучший случай бывает коротким

Оценка касается худшего случая, то есть высоты дерева. Отдельные листья могут быть близко к корню: сортировка вставками на уже отсортированном массиве делает n−1n-1 сравнение, это O(n)O(n).

3.3. Компараторы

Сортировкам сравнением не важно, что именно сортируется: достаточно уметь для двух объектов ответить, какой из них должен стоять левее. Математически это отношение линейного порядка, а в C++ — компаратор: функция, которая принимает два объекта и возвращает bool.

comparator.cpp
enum Color { Red, Orange, Yellow, Green, Blue, Indigo, Violet };  // порядок цветов радуги
 
bool by_rainbow(Color x, Color y) {
    return x < y;              // true, если x должен стоять левее y
}
 
sort(colors.begin(), colors.end(), by_rainbow);

Так можно отсортировать числа, строки в лексикографическом порядке, цвета радуги и любые свои объекты — задав компаратор или перегрузив для типа оператор <. Любая сортировка сравнением работает с ними без изменений.

Если же сортируются целые числа (или объекты по целочисленному ключу), можно не сравнивать элементы, а использовать их значения напрямую. Такие сортировки обходят оценку nlog⁡nn\log n — это линейные сортировки, следующая тема.

Частые ошибки

  1. «В Хоаре опорный средний, в Ломуто последний». Выбор опорного не зависит от схемы разбиения; различается только работа указателей.
  2. Путать, где делается работа. Слияние работает на подъёме рекурсии, быстрая сортировка — на спуске.
  3. Считать aa по числу частей, а не вызовов. В бинарном поиске массив делится на две части, но рекурсивный вызов один: a=1a=1, b=2b=2.
  4. Писать основание логарифма в асимптотике. log⁡2n\log_2n и log⁡10/9n\log_{10/9}n отличаются в константу раз — это одно и то же Θ(log⁡n)\Theta(\log n).
  5. Думать, что неровное разбиение портит асимптотику. При пропорции 1:91:9 глубина всё равно логарифмическая. Плохо, когда разбиение даёт 11 и n−1n-1.
  6. Брать опорный всегда из середины и считать это защитой. Против фиксированного выбора легко построить тест с n2n^2.
  7. Говорить, что быстрая сортировка не использует доп. память. Буфера нет, но стек рекурсии — от O(log⁡n)O(\log n) до O(n)O(n).
  8. Называть быструю сортировку устойчивой, потому что на примере порядок сохранился. Устойчивость — это гарантия для любого входа.
  9. Считать, что нижняя оценка nlog⁡nn\log n касается всех сортировок. Она верна только для сортировок сравнением; для целых чисел есть линейные сортировки.

Мини-тренажёр

  1. Найдите асимптотику: T(n)=2T(n2)+n2T(n)=2T\big(\frac n2\big)+n^2.
  2. Найдите асимптотику: T(n)=8T(n2)+n2T(n)=8T\big(\frac n2\big)+n^2.
  3. Найдите асимптотику: T(n)=9T(n3)+n2T(n)=9T\big(\frac n3\big)+n^2.
  4. Сколько уровней у дерева рекурсии слияния для n=1024n=1024?
  5. Выполните разбиение Хоара массива 4,9,2,7,5,14,9,2,7,5,1 с опорным p=5p=5. Где остановились указатели?
  6. Выполните разбиение Ломуто массива 3,8,1,6,23,8,1,6,2 с опорным p=3p=3 (опорный уже первый — сначала переставьте его в конец).
  7. Какова глубина рекурсии быстрой сортировки, если опорным всегда оказывается максимум? А если разбиение всегда 14:34\frac14:\frac34?
  8. Медиана из трёх для массива 8,3,1,7,28,3,1,7,2 — какой элемент станет опорным?
  9. Сколько листьев минимум у дерева решений для сортировки 44 элементов и какова минимальная высота?
  10. Почему быстрая сортировка не противоречит нижней оценке, хотя в среднем тоже nlog⁡nn\log n, а в худшем — n2n^2?
Ответы
  1. a=2a=2, bc=4b^c=4, a<bca<b^c — работа в корне: Θ(n2)\Theta(n^2).
  2. a=8>bc=4a=8>b^c=4 — работа в листьях: Θ(nlog⁡28)=Θ(n3)\Theta(n^{\log_28})=\Theta(n^3).
  3. a=9=32=bca=9=3^2=b^c — равенство: Θ(n2log⁡n)\Theta(n^2\log n).
  4. log⁡21024+1=11\log_21024+1=11 уровней (размеры 1024,512,…,11024,512,\dots,1).
  5. ii стоп на 99 (a1a_1), jj стоп на 11 (a5a_5): обмен, 4,1,2,7,5,94,1,2,7,5,9. Затем ii стоп на 77 (a3a_3), jj стоп на 55 (a4a_4): обмен, 4,1,2,5,7,94,1,2,5,7,9, i=4i=4, j=3j=3. Указатели пересеклись: [0;3]=4,1,2,5≤5[0;3]=4,1,2,5\le5, [4;5]=7,9≥5[4;5]=7,9\ge5.
  6. 2,8,1,6,3‾2,8,1,6,\underline3 (обменяли 33 и 22), i=0i=0. j=0j=0: 2<32<3, обмен сам с собой, i=1i=1. j=1j=1: 88 — нет. j=2j=2: 1<31<3, a1↔a2a_1\leftrightarrow a_2 — 2,1,8,6,32,1,8,6,3, i=2i=2. j=3j=3: 66 — нет. Итог: a2↔a4a_2\leftrightarrow a_4 — 2,1,3,6,82,1,\mathbf3,6,8, тройка на своём месте.
  7. Максимум каждый раз: глубина nn, время Θ(n2)\Theta(n^2). Пропорция 1:31:3: глубина log⁡4/3n=Θ(log⁡n)\log_{4/3}n=\Theta(\log n), время Θ(nlog⁡n)\Theta(n\log n).
  8. Первый 88, средний 11, последний 22 — медиана 22.
  9. 4!=244!=24 листа, 24=16<24≤32=252^4=16<24\le32=2^5 — высота не меньше 55.
  10. Нижняя оценка говорит, что худший случай не может быть лучше nlog⁡nn\log n. Быстрая сортировка в худшем случае даже хуже — n2n^2, противоречия нет. Слияние достигает оценки.

Шпаргалка

ПонятиеСуть
РекуррентаT(n)=aT(n/b)+ncT(n)=aT(n/b)+n^c: aa — вызовов, bb — во сколько раз меньше задача, ncn^c — работа вызова
Дерево рекурсииуровень ii: aia^i узлов, работа nc(a/bc)in^c(a/b^c)^i, уровней log⁡bn+1\log_bn+1
a<bca<b^cΘ(nc)\Theta(n^c) — работа в корне
a=bca=b^cΘ(nclog⁡n)\Theta(n^c\log n) — слияние nlog⁡nn\log n, бинпоиск log⁡n\log n
a>bca>b^cΘ(nlog⁡ba)\Theta(n^{\log_ba}) — работа в листьях
Быстрая сортировкаразбиение на ≤p\le p и ≥p\ge p на спуске, на подъёме ничего
Хоардва равноправных указателя навстречу, обмен неправильно стоящих
Ломутоii — граница элементов <p<p, jj — проход; опорный встаёт на своё место
Опорныйвыбор не зависит от схемы; середина — уязвима, медиана из трёх, случайный
Времялучший и средний Θ(nlog⁡n)\Theta(n\log n) (даже при 1:91:9), худший Θ(n2)\Theta(n^2)
Памятьслияние O(n)O(n); быстрая — стек O(log⁡n)O(\log n)…O(n)O(n)
Устойчивостьслияние устойчиво, быстрая — нет
Нижняя оценка≥n!\ge n! листьев ⇒\Rightarrow высота ≥log⁡2n!=Θ(nlog⁡n)\ge\log_2n!=\Theta(n\log n)
Компараторbool cmp(x, y) — сортировка сравнением работает для любого линейного порядка

Проверь себя

20 вопросов по материалу лекции. Результаты хранятся только в вашем браузере.

20 вопросов о мастер-теореме, разбиениях Хоара и Ломуто, выборе опорного элемента, времени и памяти быстрой сортировки и нижней оценке сортировок сравнением.

  • 20 вопросов
  • Результат виден сразу после каждого ответа
  • Порядок вопросов случайный

Комментарии0

Пока никто ничего не написал.

Войдите, чтобы оставить комментарий