1. Несложно о сложности. Примеры алгоритмов.
Н.Н. Кузюрин С.А. Фомин
10 октября 2008 г.
1 / 86
2. История алгоритмов
Понятие алгоритма известно с незапамятных времен
Алгоритм Евклида (Euclidean algorithm) — 500-300 гг. д.н.э.
Решето Эратосфена (Sieve of Eratosthenes) — 300-200 гг. д.н.э.
Формализация понятия — 1930–1940 годы.
Курт Гёдель ⇒ «неполнота формальной арифметики», 1931.
Алан Тьюринг ⇒ «halting problem», 1936.
Эмиль Пост ⇒ «машина Поста», 1936.
Алонзо Чёрч ⇒ «An Unsolvable Problem of Elementary Number
Theory», 1936.
Стивен Клини ⇒ «Тезис Черча-Тьюринга», 1943.
2 / 86
3. История алгоритмов
Понятие алгоритма известно с незапамятных времен
Алгоритм Евклида (Euclidean algorithm) — 500-300 гг. д.н.э.
Решето Эратосфена (Sieve of Eratosthenes) — 300-200 гг. д.н.э.
Формализация понятия — 1930–1940 годы.
Курт Гёдель ⇒ «неполнота формальной арифметики», 1931.
Алан Тьюринг ⇒ «halting problem», 1936.
Эмиль Пост ⇒ «машина Поста», 1936.
Алонзо Чёрч ⇒ «An Unsolvable Problem of Elementary Number
Theory», 1936.
Стивен Клини ⇒ «Тезис Черча-Тьюринга», 1943.
3 / 86
4. История алгоритмов
Понятие алгоритма известно с незапамятных времен
Алгоритм Евклида (Euclidean algorithm) — 500-300 гг. д.н.э.
Решето Эратосфена (Sieve of Eratosthenes) — 300-200 гг. д.н.э.
Формализация понятия — 1930–1940 годы.
Курт Гёдель ⇒ «неполнота формальной арифметики», 1931.
Алан Тьюринг ⇒ «halting problem», 1936.
Эмиль Пост ⇒ «машина Поста», 1936.
Алонзо Чёрч ⇒ «An Unsolvable Problem of Elementary Number
Theory», 1936.
Стивен Клини ⇒ «Тезис Черча-Тьюринга», 1943.
4 / 86
5. История алгоритмов
Понятие алгоритма известно с незапамятных времен
Алгоритм Евклида (Euclidean algorithm) — 500-300 гг. д.н.э.
Решето Эратосфена (Sieve of Eratosthenes) — 300-200 гг. д.н.э.
Формализация понятия — 1930–1940 годы.
Курт Гёдель ⇒ «неполнота формальной арифметики», 1931.
Алан Тьюринг ⇒ «halting problem», 1936.
Эмиль Пост ⇒ «машина Поста», 1936.
Алонзо Чёрч ⇒ «An Unsolvable Problem of Elementary Number
Theory», 1936.
Стивен Клини ⇒ «Тезис Черча-Тьюринга», 1943.
5 / 86
6. Теория сложности
Ресурсные ограничения
Время
Память
Объем коммуникаций
Переборные алгоритмы
Пригодны для любой задачи разрешения, но время работы растет
экспоненциально.
Теория сложности
Формулирует алгоритмические задачи. Для каждой задачи ищет:
Эффективные алгоритмы — верхние оценки затрат (времени, памяти,
. . .)
Доказательства сложности — нижние оценки затрат.
6 / 86
7. Теория сложности
Ресурсные ограничения
Время
Память
Объем коммуникаций
Переборные алгоритмы
Пригодны для любой задачи разрешения, но время работы растет
экспоненциально.
Теория сложности
Формулирует алгоритмические задачи. Для каждой задачи ищет:
Эффективные алгоритмы — верхние оценки затрат (времени, памяти,
. . .)
Доказательства сложности — нижние оценки затрат.
7 / 86
8. Теория сложности
Ресурсные ограничения
Время
Память
Объем коммуникаций
Переборные алгоритмы
Пригодны для любой задачи разрешения, но время работы растет
экспоненциально.
Теория сложности
Формулирует алгоритмические задачи. Для каждой задачи ищет:
Эффективные алгоритмы — верхние оценки затрат (времени, памяти,
. . .)
Доказательства сложности — нижние оценки затрат.
8 / 86
9. Обозначения
f (n) = O(g (n))
Существует константа C > 0 такая, что начиная с некоторого n
выполнено f (n) ≤ Cg (n).
f (n) = Ω(g (n))
Существует константа C > 0 такая, что начиная с некоторого n
выполнено f (n) ≥ Cg (n).
Описание алгоритмов
«Псевдокод» — неполнота и ошибочность,
«C/C++/Java» — нечитаемый синтаксис и слабая абстракция.
Мы используем популярный и рекомендованный для преподавания
алгоритмов язык Python.
9 / 86
10. Обозначения
f (n) = O(g (n))
Существует константа C > 0 такая, что начиная с некоторого n
выполнено f (n) ≤ Cg (n).
f (n) = Ω(g (n))
Существует константа C > 0 такая, что начиная с некоторого n
выполнено f (n) ≥ Cg (n).
Описание алгоритмов
«Псевдокод» — неполнота и ошибочность,
«C/C++/Java» — нечитаемый синтаксис и слабая абстракция.
Мы используем популярный и рекомендованный для преподавания
алгоритмов язык Python.
10 / 86
11. Тривиальное вычисление y = x n mod m
13 16 47
13
28
35
def mod_exp (x, n, m) : 32
print x, n, m 40
y ←1 3
for i ∈ range (n) : 39
y ←y ∗x %m 37
11
print y
2
return y 26
9
Количество умножений — O(n) 23
17
33
6
y = 13^16 (mod 47) = 6
11 / 86
12. Разумное вычисление y = x n mod m
k
k i i i
xn = x i=0 ai 2 = x ai 2 = x2
i=0 {i:ai >0}
def mod_exp (x, n, m) :
print x, n, m 13 16 47
y ←1 28 8 1
X ←x 32 4 1
N←n 37 2 1
while N > 0 : 6 1 1
if N % 2 = 1 : 36 0 6
y ←y ∗X %m y = 13^16 (mod 47) = 6
X ←X ∗X %m
N ← N/2 Количество арифметических
print X , N, y операций — O(log(n)).
return y
Длина (бит) Умножений в алг. 1 Умножений в алг. 2
56 256 ≈ 7.2 · 1016 ≈ 100
128 2128 ≈ 3.4 · 1038 ≈ 130
12 / 86
13. Вычисление факториала y = n! mod m
def factorial (n, m) :
print n, m 13 131
y ←1 1
for i ∈ range (1, n + 1) : 2
y ←y ∗i %m 6
print y 24
return y 120
65
Количество умножений — O(n). 62
Временная сложность измеряется 103
относительно длины входа: 10
log n + log m. 100
Поэтому cложность 52
экспоненциальна ! 100
Возможно ли лучше — открытая 121
проблема. y =13! mod 131 = 121
13 / 86
14. Дискретный логарифм
Задача
«Дискретный логарифм» (Discrete logarithm) Даны натуральные a, b,
и p — нечетное простое число. Найти минимальный x, такой, что
ax ≡ b (mod p).
Вычисление дискретного логарифма является очень сложной задачей.
Самые быстрые из известных алгоритмов требуют
сверхполиномиального времени.
На этом свойстве односторонней вычислимости модульной экспоненты
основано множество алгоритмов современной криптографии.
14 / 86
15. Дискретный логарифм
Задача
«Дискретный логарифм» (Discrete logarithm) Даны натуральные a, b,
и p — нечетное простое число. Найти минимальный x, такой, что
ax ≡ b (mod p).
Вычисление дискретного логарифма является очень сложной задачей.
Самые быстрые из известных алгоритмов требуют
сверхполиномиального времени.
На этом свойстве односторонней вычислимости модульной экспоненты
основано множество алгоритмов современной криптографии.
15 / 86
16. Дискретный логарифм
Задача
«Дискретный логарифм» (Discrete logarithm) Даны натуральные a, b,
и p — нечетное простое число. Найти минимальный x, такой, что
ax ≡ b (mod p).
Вычисление дискретного логарифма является очень сложной задачей.
Самые быстрые из известных алгоритмов требуют
сверхполиномиального времени.
На этом свойстве односторонней вычислимости модульной экспоненты
основано множество алгоритмов современной криптографии.
16 / 86
18. Алгоритм Евклида
Базовое соотношение
gcd(a, b) = gcd(a, r ), b = at + r , 0 ≤ r < a.
Calculating gcd(123456, 6122256):
123456 6122256
72912 123456
50544 72912
def gcd (a, b) : 22368 50544
5808 22368
print a, b 4944 5808
if a = 0 : 864 4944
return b 624 864
240 624
return gcd (b % a, a) 144 240
96 144
48 96
0 48
gcd(123456, 6122256) = 48
18 / 86
19. Алгоритм Евклида
Базовое соотношение
gcd(a, b) = gcd(a, r ), b = at + r , 0 ≤ r < a.
Calculating gcd(123456, 6122256):
123456 6122256
72912 123456
50544 72912
def gcd (a, b) : 22368 50544
5808 22368
print a, b 4944 5808
if a = 0 : 864 4944
return b 624 864
240 624
return gcd (b % a, a) 144 240
96 144
48 96
0 48
gcd(123456, 6122256) = 48
19 / 86
20. Алгоритм Евклида: Время выполнения
Лемма
Время работы алгоритма Евклида — O(log a + log b) арифметических
операций.
Доказательство.
1 Имеем b ≥ a + (b mod a) ≥ 2(b mod a) ≡ 2r .
2 Отсюда получаем, что r ≤ b .
2
3 ar ≤ ab/2 (на каждой итерации ab уменьшается вдвое).
4 После log(ab) итераций ab станет нулем.
5 ab = 0 → a = 0 → НОД найден.
20 / 86
21. Алгоритм Евклида: Время выполнения
Лемма
Время работы алгоритма Евклида — O(log a + log b) арифметических
операций.
Доказательство.
1 Имеем b ≥ a + (b mod a) ≥ 2(b mod a) ≡ 2r .
2 Отсюда получаем, что r ≤ b .
2
3 ar ≤ ab/2 (на каждой итерации ab уменьшается вдвое).
4 После log(ab) итераций ab станет нулем.
5 ab = 0 → a = 0 → НОД найден.
21 / 86
22. Алгоритм Евклида: Время выполнения
Лемма
Время работы алгоритма Евклида — O(log a + log b) арифметических
операций.
Доказательство.
1 Имеем b ≥ a + (b mod a) ≥ 2(b mod a) ≡ 2r .
2 Отсюда получаем, что r ≤ b .
2
3 ar ≤ ab/2 (на каждой итерации ab уменьшается вдвое).
4 После log(ab) итераций ab станет нулем.
5 ab = 0 → a = 0 → НОД найден.
22 / 86
23. Алгоритм Евклида: Время выполнения
Лемма
Время работы алгоритма Евклида — O(log a + log b) арифметических
операций.
Доказательство.
1 Имеем b ≥ a + (b mod a) ≥ 2(b mod a) ≡ 2r .
2 Отсюда получаем, что r ≤ b .
2
3 ar ≤ ab/2 (на каждой итерации ab уменьшается вдвое).
4 После log(ab) итераций ab станет нулем.
5 ab = 0 → a = 0 → НОД найден.
23 / 86
24. Алгоритм Евклида: Время выполнения
Лемма
Время работы алгоритма Евклида — O(log a + log b) арифметических
операций.
Доказательство.
1 Имеем b ≥ a + (b mod a) ≥ 2(b mod a) ≡ 2r .
2 Отсюда получаем, что r ≤ b .
2
3 ar ≤ ab/2 (на каждой итерации ab уменьшается вдвое).
4 После log(ab) итераций ab станет нулем.
5 ab = 0 → a = 0 → НОД найден.
24 / 86
25. Алгоритм Евклида: Время выполнения
Лемма
Время работы алгоритма Евклида — O(log a + log b) арифметических
операций.
Доказательство.
1 Имеем b ≥ a + (b mod a) ≥ 2(b mod a) ≡ 2r .
2 Отсюда получаем, что r ≤ b .
2
3 ar ≤ ab/2 (на каждой итерации ab уменьшается вдвое).
4 После log(ab) итераций ab станет нулем.
5 ab = 0 → a = 0 → НОД найден.
25 / 86
26. Задача Коммивояжера
Задача
«Коммивояжер», «TSPa ». Заданы неориентированный граф из n
вершин-городов, и dij ≡ d(vi , vj ) — положительные целые расстояния
между городами.
Чему равна наименьшая возможная длина кольцевого маршрута,
проходящего по одному разу через все города? Т.е. нужно найти
минимально возможное значение суммы
n−1
min dpi ,pi+1 + dpn ,p1 , (1)
1 2 . . . n i=1
p∈
. . . .
где минимум берется по всем перестановкам p чисел 1, . . . , n.
a
В англоязычной литературе — Traveling Salesman Problem.
26 / 86
27. Переборный алгоритм для TSP
def TSP_BruteForce (G ) :
MinPath ← MinPathLength ← None
перебор всех перестановок с фиксированным первым узлом
for path ∈ xpermutations (G .nodes ()[1 : ]) :
PathLength ← getPathLength (path, G .nodes ()[0])
if ¬MinPathLength ∨ MinPathLength > PathLength :
MinPathLength, MinPath ← PathLength, path
return MinPath, MinPathLength
27 / 86
28. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
28 / 86
29. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
29 / 86
30. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
30 / 86
31. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
31 / 86
32. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
32 / 86
33. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
33 / 86
34. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
34 / 86
35. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
35 / 86
36. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
36 / 86
37. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
37 / 86
38. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
38 / 86
39. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
39 / 86
40. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
40 / 86
41. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
41 / 86
42. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
42 / 86
43. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
43 / 86
44. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
44 / 86
45. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
45 / 86
46. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
46 / 86
47. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
47 / 86
48. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
48 / 86
49. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
49 / 86
50. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
50 / 86
51. Перебор для TSP
Moscow
$50
$10
Berlin $30
$60
Kiev
$15
$50 $20
$80
$15
NY $120
Minsk
51 / 86
53. Кратчайшие пути в графе
Задача
«Кратчайший путь в графе»a .
Заданы n вершин графа (узлов сети) v1 , v2 , . . . , vn и положительные
целые длины дуг dij ≡ d(vi , vj ) между ними.
Нужно для всех k ∈ (2 . . . n) найти минимальную длину пути из v1 в vk .
a
В англоязычной литературе — Shortest Path Problem.
53 / 86
54. Кратчайшие пути в графе
Важное свойство
Если у нас есть кратчайший путь от v до w , проходящий через
вершину y , назовем его (v → w )∗ , то его первая часть от v до y ,
(v → y )∗ , тоже будет кратчайшим путем.
Доказательство.
Если бы существовал бы путь (v → y )! длины меньшей, чем (v → y )∗ ,
то можно было бы улучшить оптимальный путь (v → w )∗ , заменив
в нем (v → y )∗ на (v → y )! .
54 / 86
55. Алгоритм Дейкстры
def dijkstra (G , startNode) :
Visited ← {} # хэш (узел → стоимость) посещенных вершин
ToVisit ← {startNode : 0} # соседи посещенных (уз. → стоим.)
Paths ← {startNode : [startNode]} # узел → кратчайший путь
while ToVisit : # пока есть куда стремиться
v ← argmin (ToVisit) # выбираем ближайшую
Visited[v ] ← ToVisit[v ] # фиксируем откуда пришли в v
del ToVisit[v ] # кратчайший путь к v найден
for w ∈ G .neighbors (v ) : # для всех соседей вершины v
if (w ∈ Visited) : # еще не нашли кратчайший путь
обновляем кратчайшие пути
vwLength ← Visited[v ] + G .get_edge (v , w )
if (w ∈ ToVisit) ∨ (vwLength < ToVisit[w ]) :
ToVisit[w ] ← vwLength # обновляем цену
Paths[w ] ← Paths[v ] + [w ] # посещения соседа
return (Visited, Paths)
55 / 86
63. Трудоемкость алгоритма Дейкстры
Лемма
Трудоемкость алгоритма Дейкстры составляет O(n2 ) операций, где
n — число вершин.
Доказательство.
1 Внешний цикл по вершинам дает множитель n.
2 Внутренний цикл содержит выбор минимального элемента — O(n)
+ пересчет оценок длин для соседей выбранного узла — O(n).
3 Итого — O(n2 ).
63 / 86
64. Трудоемкость алгоритма Дейкстры
Лемма
Трудоемкость алгоритма Дейкстры составляет O(n2 ) операций, где
n — число вершин.
Доказательство.
1 Внешний цикл по вершинам дает множитель n.
2 Внутренний цикл содержит выбор минимального элемента — O(n)
+ пересчет оценок длин для соседей выбранного узла — O(n).
3 Итого — O(n2 ).
64 / 86
65. Трудоемкость алгоритма Дейкстры
Лемма
Трудоемкость алгоритма Дейкстры составляет O(n2 ) операций, где
n — число вершин.
Доказательство.
1 Внешний цикл по вершинам дает множитель n.
2 Внутренний цикл содержит выбор минимального элемента — O(n)
+ пересчет оценок длин для соседей выбранного узла — O(n).
3 Итого — O(n2 ).
65 / 86
66. Кратчайшие пути в графе с отрицательными весами
Задача
«Кратчайшие пути с отрицательными расстояниями».
Задан ориентированный граф G = (V , E ) и весовая функция на дугах
we : e → Z , отображающая ребра в целые числа, такая, что в графе
нет цикла отрицательной длины. Найти минимальные длины путей
между всеми парами вершин.
66 / 86
67. Алгоритм Флойда-Уоршолла
for k ∈ range (N) : # N — размер матрицы
DD ← array (D) # Сохраняем Dk−1 в DD
for v1 ∈ range (N) :
for v2 ∈ range (N) :
D[v1, v2] ← min (DD[v1, v2], DD[v1, k] + DD[k, v2])
67 / 86
73. Минимальное остовное дерево
Задача
«Минимальное остовное дерево» (Minimum Spanning Tree)
Задан связный неориентированный граф G = (V , E ), где
V —множество вершин, |V | = n, E —множество ребер между ними,
и весовая функция w : E → Z +. Иными словами, есть n вершин
v1 , . . . , vn и положительные целые веса дуг wij ≡ w (vi , vj )a между ними.
Требуется найти наименьший возможный вес остовного дерева, т.е.
min w (vi , vj ), (2)
(i,j)∈T
где минимум берется по всем остовным деревьям на n вершинах (по
всем множествам T из (n − 1) дуг, связывающим все n вершин
в единую сеть).
a
Можно вводить веса на ребрах, как we , e ∈ E .
73 / 86
74. Алгоритм Прима
def MST_Prim (G , s) :
MST ← {} # мин. остовное дерево, хэш (вершина:предшественник)
ToVisit ← {s : 0} # хэш, граничащих с MST, (узел:стоимость)
Predecessor ← {s : s} # хэш: вершины из которых включают другие
while ToVisit : # пока есть непосещенные вершины
v ← argmin (ToVisit) # ближайшая достижимая вершина
MST[v ] ← Predecessor[v ]; # запоминаем, откуда пришли
del ToVisit[v ]; del Predecessor[v ]; # больше не посещать
for w ∈ G .neighbors (v ) : # для всех соседей вершины v
if w ∈ MST : # которые еще не в MST
обновляем стоимость включения в MST
if w ∈ ToVisit ∨ G .get_edge (v , w ) < ToVisit[w ] :
ToVisit[w ] ← G .get_edge (v , w ) # кандидат
Predecessor[w ] ← v
return MST
74 / 86
75. Выполнение алгоритма Прима
Berlin ($20)
$50
Moscow ($15) $10 $30
Kiev ($15)
$60 $$ 2 0
$15 0
5
$80 $15
NY
Minsk
Start
Итерация № 1 Стоимость MST: 0
75 / 86
76. Выполнение алгоритма Прима
Berlin ($20)
$50
Moscow $30
$10
$ 5 0$ 2 0 Kiev ($10)
$60 $80
$15
$15
NY ($60)
Minsk
Start
Итерация № 2 Стоимость MST: 15
76 / 86
77. Выполнение алгоритма Прима
Berlin ($20)
$50
Moscow $10 $30
$50 $20 Kiev
$60
$15 $15
$80
NY ($60)
Minsk
Start
Итерация № 3 Стоимость MST: 25
77 / 86
78. Выполнение алгоритма Прима
Berlin
$50
Moscow $10 $30
$50 $20 Kiev
$60
$15 $15
$80
NY ($50)
Minsk
Start
Итерация № 4 Стоимость MST: 45
78 / 86
79. Выполнение алгоритма Прима
Berlin
$50
Moscow $10 $30
$50 $20 Kiev
$60
$15 $15
$80
NY
Minsk
Start
Итерация № 5 Стоимость MST: 95
79 / 86
80. Сортировка
Задача
«Сортировка» (Sorting)
Имеется произвольный массив A : a1 , . . . , an .
Tребуется путем сравнений отсортировать этот массив таким образом,
чтобы элементы расположились в порядке возрастания (или
убывания), то есть ai1 ≤ ai2 ≤ . . . ≤ ain .
80 / 86
81. Cортировка слиянием
def mergesort (L) :
M ← len (L)/2 # середина списка
if M = 0 : # если список меньше двух элементов
return L # сортировать нечего
return merge (mergesort (L[ : M]), mergesort (L[M : ]))
def merge (A, B) :
C ← []
while A ∨ B : # пока оба списка непусты
if ¬B ∨ (A ∧ A[0] < B[0]) :
C .append (A.pop (0)) # A0 удаляем из A и добавляем в C
else :
C .append (B.pop (0)) # B0 удаляем из B и добавляем в C
return C
81 / 86
83. Cортировка слиянием: Упражнения
Упражнение
Найдите такие упорядоченные последовательности A и B, на которых
процедура «merge» выполнит |A| + 1 сравнений.
Упражнение
Найдите такие упорядоченные последовательности A и B, на которых
процедура «merge» выполнит |A| + |B| − 1 сравнений.
83 / 86
84. Cортировка слиянием: Время выполнения
Пусть T (n) — число сравнений, достаточное для сортировки слиянием.
T (n) ≤ 2T (n/2) + O(n).
Проверим T (n) = cn log2 n:
cn log2 n ≤ cn log(n/2) + O(n) = cn log2 n − cn + O(n)
Резюме
Алгоритм асимптотически оптимален: O(n log n), но использует
вспомогательные массивы (не всегда допустимо).
84 / 86