
- •Алгоритмы на графах с нагруженными вершинами (Сортировка) Дерево сортировки и сортировка деревом
- •Быстрая сортировка Алгоритм
- •Детали реализации
- •Сортировка слиянием
- •Цифровая сортировка
- •Алгоритм
- •Cортировка цепочек
- •Алгоритм
- •Алгоритмы на графах с нагруженными ребрами (Кратчайшие пути и смежные вопросы)
- •Кратчайший путь от фиксированной вершины
Алгоритмы на графах с нагруженными вершинами (Сортировка) Дерево сортировки и сортировка деревом
Двоичное дерево, узлы которого нагружены таким образом, что вес каждого узла не меньше веса любого узла в его поддереве – дерево сортировки.
Последовательность весов на любом пути от предка к потомку линейно упорядочена, максимум в корне.
Подходящая структура данных для хранения дерева с нагруженными вершинами – линейный массив S = <a1, …, an>, где a1 – вес в корне дерева, а для узла с весом ai веса сыновей соответственно a2i и a2i+1.
Быстрая сортировка Алгоритм
Данные: последовательность S = <a1, …, an>
Результат: то же, последовательность упорядочена.
Quicksort(S) {
if (|S| <= 1) return (S);
else {
(Выбрать произвольный элемент a из S );
(Разделить последовательность S на три части:
S1 с элементами меньше a, S2 – равными a,
S3 – больше a );
return( <Quicksort(S1), S2, Quicksort(S3)> );
}
}
Временная сложность: O (n log n) в среднем при условии равновероятного выбора элемента a.
Детали реализации
1. Выбор a. Если брать определенный элемент, например, всегда первый – получаем оценку сложности O (n2). Можно генерировать случайное число i из интервала [1…n] и брать a = Ai. Более простой способ: взять выборку элементов из S и использовать медиану (можно рассмотреть, например, 1‑й, средний и последний элементы).
2. Разбиение. Удобно реализовать все этапы сразу. Так как функция вызывается рекурсивно, аргумент всегда будет частью исходной последовательности A[f], A[f+1], … A[l]. Выбрав произвольный элемент A[i] = a, можно разбить в этом месте.
Можно использовать следующий алгоритм разбиения с помощью рабочих индексов i, j:
i=f;
j=l;
while (i <= j) {
while ((A[j] >= a ) && (j >= f) j--;
while ((A[j]< a ) && (i <= l) i++;
if (i < j) {
{Обменять A[i], A[j]};
i++; j--;
}
}
Замечание: аргументами Quicksort могут быть (f, l) – номера элементов массива.
Сортировка слиянием
Алгоритм
LinkSort(i, j) {
if (i=j) return(A[i]);
else {
m=(i+j-1)/2;
return ( Слияние (LinkSort(1,m), LinkSort(m+1, j));
}
}
Сложность: O (n log n).
Функция “Слияние” просматривает поэлементно две заданные последовательности и отбирает в третью последовательность (результат) меньший из двух текущих элементов.
Цифровая сортировка
Рассмотрим последовательность целых <a1, …, ai, …, an> , ai [0, m-1]. Если значение m не слишком велико, последовательность можно упорядочить, используя следующий алгоритм:
-
организовать m пустых очередей – по одной для каждого из чисел 0 m‑1 – черпаков;
-
просматривая последовательность <a1, …, an> слева направо, поместить каждый ее элемент ai в очередь с номером, равным значению этого элемента (в очередь № ai);
-
сцепить полученные очереди в порядке возрастания номеров.
Этот алгоритм известен под названием сортировка вычерпыванием. Очевидно, что его временная сложность O (n). Она определяется пунктом 2 алгоритма, поскольку пункты 1 и 3 выполняются за постоянное время (не зависящее от n).
Алгоритм цифровой или поразрядной сортировки является естественным обобщением алгоритма сортировки вычерпыванием для кортежей.
Кортеж – это набор значений <s1,… si,… , sp>, поставленный в соответствие каждому элементу сортируемой последовательности, причем i, si[0, mi-1] и (s1, … , sp) (t1, … , tq) выполнено одно из условий:
-
j, sj < tj и i < j, si = ti;
-
p q и si = ti , i [1, p].
Будем считать для простоты, что i, mi = m.
Последовательность кортежей можно отсортировать за k проходов: сначала по k‑той позиции, потом по (k – 1)-й, и т. д. до 1‑й.