- •1Введение
- •2Сортировки
- •2.1Сортировки массивов
- •2.2Сортировка простым включением
- •2.3Сортировка простым выбором
- •2.4Сортировка простым обменом
- •2.5Сравнение простых сортировок
- •2.6 Сортировка шелла
- •2.7Пирамидальная сортировка
- •2.8Быстрая сортировка
- •2.9Поиск медианы и квантилей
- •2.10Сравнение сортировок
- •3Поиск подстроки в строке
- •3.1Поиск в строке
- •3.2Простой поиск в строке
- •3.3Поиск в строке. Алгоритм боуера-мура
- •4Генерация перестановок
- •4.1Генерация перестановок последовательности натуральных чисел
- •4.2Генерация перестановок элементов в антилексикографическом порядке
- •4.3Генерация перестановок за одну транспозицию элементов
- •4.4Генерация перестановок за одну транспозицию соседних элементов
- •5Генерация подмножеств
- •5.1Генерация всех подмножеств множества
- •5.2Генерация m -элементных подмножеств множества натуральных чисел
- •Var m: integer; {Размер подмножества}
- •Var I, j, p: integer;
- •5.3Генрация k-компонентных выборок на множестве {0, 1}
- •Var k: integer; {Количество нулей в кортеже}
- •I: integer;
- •Var I, j, p: integer;
- •If Finish then Break {Exit};
- •6Генерация разбиений
- •6.1Разбиение целых чисел
- •Var I, j: integer;
- •Var j: integer;
- •Var I, j, k: integer;
- •Var d, l, Sum: integer;
- •6.2Разбиение множеств
- •/1, 2, 3/ И /4/ затем /1, 2/ и /3, 4/ и т.Д. }
- •I, j, k, r, s: integer;
- •If not Flag2 then
- •If Flag1 then
- •If Forvd[j] then { j движется вперед}
- •7Обходы бинарных деревьев
- •7.1Процедуры прохождения бинарных деревьев
- •8Поиск на бинарных деревьях
- •8.1Процедуры поиска на бинарных деревьях
- •Рекомендованная литература
2.1Сортировки массивов
Основное требование - экономия памяти. Это означает, что переупорядочивание массивов нужно выполнить на том же месте, а не заниматься пересылками из массива в массив.
Алгоритмы сортировки массивов классифицируются в соответствии с их эффективностью, т.е. экономией времени или быстродействием.
Удобная мера эффективности получается при подсчета числа С - необходимых сравнений ключей и числа М - пересылок элементов. Эти числа пропорциональны n - количеству элементов массива.
Простые - очевидные сортировки, требуют порядка n2 сравнений, а полученные на их основе хорошие алгоритмы требуют порядка n * log2n.
Например, при n = 64 в первом случае получим порядка 4096 сравнений, а во втором 384 сравнения.
Методы сортировки массивов можно разбить на три класса, в зависимости от лежащего в их основе приема:
Сортировка включением.
Сортировка выбором.
Сортировка обменом.
Будем различать простые сортировки данных классов, например “Сортировка простым включением” и эффективные сортировки данных классов или просто сортировки данных классов, например “Сортировка включением”.
Для описания этих сортировок будем использовать динамические массивы Delphi, что позволит сделать процедуры сортировки, независимые от размера массивов.
Введем дополнительно следующие типы данных и переменные:
type
TArr: array of Item;
var A: TArr;
2.2Сортировка простым включением
Хорошая ассоциация метода сортировки простым включением (СПВкл)- упорядочивание сданных карт, которое выполняют, например, игроки в преферанс перед началом очередной партии. В пределах одной масти карты упорядочивают по возрастанию (убыванию), вынимая некоторую карту из набора и сдвигая на её место все остальные карты, расположенные слева (справа) от неё, пока не освободится место, на которое должна быть вставлена вынутая карта.
Суть алгоритма в следующем: Элементы массива (карты) разделяются на готовую последовательность, в пределах которой все элементы уже упорядочены
а1, а2,....., аi-1
и входную последовательность
аi, ...., аn
элементы которой пополняют готовую последовательность и занимают в ней соответствующее место. Для этого на каждом шаге, начиная с i = 2 и увеличивая i на 1, берут i-тый элемент входной последовательности и передают его в готовую последовательность, путем вставки этого элемента в нужное место и сдвига всех элементов, которые расположены слева от i-того элемента, на одну позицию вправо до тех пор, пока не будет найдено нужное место.
Пример. Начальные ключи:
44, 55, 11, 33, 99, 22, 01, 77
i = 2, т.е. взят элемент 55 и выполняется попытка сдвинуть его влево. Попытка неудачна, т.к. 55 относительно 44 на своём месте.
Таким образом:
44, 55, 11, 33, 99, 22, 01, 77
44, 55, 11, 33, 99, 22, 01, 77
i = 3, т.е. взят элемент 11 и он заносится на первое место, а 44 и 55 сдвигаются на одну позицию вправо.
Таким образом:
4
4,
55, 11, 33, 99, 22, 01, 77
11, 44, 55, 33, 99, 22, 01, 77
И далее:
i = 4 11, 33, 44, 55, 99, 22, 01, 77
i = 5 11, 33, 44, 55, 99, 22, 01, 77
i = 6 11, 22, 33, 44, 55, 99, 01, 77
i = 7 01, 11, 22, 33, 44, 55, 99, 77
i = 8 01, 11, 22, 33, 44, 55, 77, 99
Таким образом, имеем два цикла. Внешний цикл пробегает значения от i = 2 до i = N, а внутренний цикл от j = i до наступления одного из дух следующих событий:
1. aj < ai < aj+1 и 1 < j < i, т.е. найдено место внутри готовой последовательности;
2. j =1, т.е. ai является самым малым элементом и вставляется на первое место в "готовой" последовательности.
Таким образом, внешний цикл целесообразно представить оператором “for”, а внутренний оператором “while”.
Необходимые типы, переменные и процедура имеют следующий вид:
type TArr = array of Item ;
var A: TArr;
procedure StraightInsrtion (var A: TArr);
var I, J: integer;
N: integer; {количество элементов сортируемой последовательности}
X: Item;
begin
N := Length (A);
for I := 1 to N-1 do
begin
X := A[I];
J := I - 1;
while (X.Key < A[J].Key) and (J >= 0) do
begin
A[J+1] := A[J];
J := J – 1;
end;
A[J+1] := X;
end;
end; {StraightInsertion}
begin
{формирование и заполнение массива А}
ShellSort (A); {сортировка массива}
···
end.
Проведенный анализ показал, что число сравнений С и перестановок М имеет следующие характеристики:
Cmin = n – 1 Mmin = 2(n -1)
Cmax = 1/2(n2 + n) – 1 Mmax = 1/4(n2 + 9n - 10)
Cavg = 1/4(n2 + n - 2) Mavg = 1/2(n2 + 3n - 4)
и зависит от состояния исходного массива.
Алгоритм СПВкл легко можно улучшить исходя из того, что готовая последовательность а1 ,....., аi-1, в которую нужно включать новый элемент, уже упорядочена. В результате для поиска места включения можно применить метод бинарного поиска, суть которого в следующем: исследуется средний элемент готовой последовательности и продолжается деление пополам, пока не будет найдено место включения. В результате для заданного значения i количество сравнений сокращается в среднем с i/2 до log2i.
Этот механизм называется сортировкой с бинарным включением (СБВкл) и имеет вид:
procedure BinaryInsertion (var A: TArr);
var I, J, L, R, M: integer;
X: Item;
N: integer; {количество элементов сортируемой последовательности}
begin
N := Length (A);
for I := 1 to N-1 do
begin
X := A[I];
L := 1;
R := I-1;
while L <= R do
begin
M := (L + R) div 2;
{определяется местоположение среднего элемента}
if X.Key < A[M].Key then R := M - 1 else L := M + 1;
end;
for J := I – 1 downto L do A[J+1] := A[J];
A[L] := X;
end;
end; {BinaryInsertion}
Алгоритм СБВкл позволяет сократить количество сравнений, но не перестановок.
Следует подчеркнуть, что перестановки требуют значительно больше времени, чем сравнения и поэтому в первую очередь следует сокращать количество перестановок.
В этом смысле сортировка включением оказывается не очень подходящей, т.к. включение элемента с последующим сдвигом ряда элементов на одну позицию неэффективно.
Лучших результатов можно ожидать от метода, при котором пересылки элементов выполняются только для отдельных элементов и на большом расстоянии. Эта мысль приводит к сортировке выбором.
