Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СиАОД / SD4-1.doc
Скачиваний:
20
Добавлен:
01.05.2014
Размер:
60.42 Кб
Скачать

Алгоритмы на графах с нагруженными вершинами (Сортировка) Дерево сортировки и сортировка деревом

Двоичное дерево, узлы которого нагружены таким образом, что вес каждого узла не меньше веса любого узла в его поддереве – дерево сортировки.

Последовательность весов на любом пути от предка к потомку линейно упорядочена, максимум в корне.

Подходящая структура данных для хранения дерева с нагруженными вершинами – линейный массив 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 не слишком велико, последовательность можно упорядочить, используя следующий алгоритм:

  1. организовать m пустых очередей – по одной для каждого из чисел 0  m1черпаков;

  2. просматривая последовательность <a1, …, an> слева направо, поместить каждый ее элемент ai в очередь с номером, равным значению этого элемента (в очередь № ai);

  3. сцепить полученные очереди в порядке возрастания номеров.

Этот алгоритм известен под названием сортировка вычерпыванием. Оче­вид­но, что его временная сложность O (n). Она определяется пунктом 2 ал­го­рит­ма, поскольку пункты 1 и 3 выполняются за постоянное время (не за­висящее от n).

Алгоритм цифровой или поразрядной сортировки является естественным об­общением алгоритма сортировки вычерпыванием для кортежей.

Кортеж – это набор значений <s1,… si,… , sp>, поставленный в соответствие каждому элементу сортируемой последовательности, причем i, si[0, mi-1] и (s1, … , sp)  (t1, … , tq)  выполнено одно из условий:

  1. j, sj < tj и  i < j, si = ti;

  2. p  q и si = ti , i  [1, p].

Будем считать для простоты, что i, mi = m.

Последовательность кортежей можно отсортировать за k проходов: сначала по kтой позиции, потом по (k1)-й, и т. д. до 1‑й.

Соседние файлы в папке СиАОД