Комбинированный урок №13
Тема: Сортировка и поиск информации. Методы внутренней сортировки
Цель: изучить методы внутренней сортировки такие как.
Сортировка и поиск информации
Вся человеческая деятельность связана с поиском и упорядочиванием.
Почему так устроена человеческая натура? Оказывается потому, что поиск в упорядоченном массиве значительно эффективнее! Ведь в природе зачастую успешность деятельности зависит от быстроты выбора правильного решения. Поэтому, если у вас в голове все знания упорядочены, вы достигаете больших успехов.
Используя структурированный тип Record, создаются массивы записей всевозможных баз данных (информация о студентах Вуза, информация о товарах в магазине, информация о машинном парке и др.).
При этом алгоритмами решения этих задач являются «поиск» и «сортировка», которые существенно зависят от того, организованы записи в массивы или размещены на диске.
Обычно запись содержит некое ключевое слово (ключ), по которому ее находят среди множества других аналогичных записей. В зависимости от решаемой задачи ключом может, например, служить фамилия или учетный номер, или адрес. Основное требование к ключу в задачах поиска и сортировки состоит в том, чтобы операция проверки на равенство была корректной. Поэтому, например, в качестве ключа не следует выбирать действительное число, т.к. из-за всегда возможной ошибки округления, поиск нужного ключа может оказаться безрезультатным, хотя этот ключ в массиве имеется. Для применения более эффективных методов поиска значения ключей должны допускать упорядоченность (т.е. проверку на > или <). Желательно, чтобы в массиве записей не было повторяющихся ключей.
Под сортировкой понимают процесс переупорядочивания некоторого множества объектов с целью их размещения в заданном порядке. Это универсальный вид деятельности с точки зрения обработки данных, которые представляют собой последовательность ключей. С помощью сортировки добиваются такого их размещения, чтобы было выполнено условие: f(a[1]) f(a[2])f(a[3])… f(a[N]), где символ означает знак предшествования, а f -некоторая функция упорядочивания. При упорядочивании по возрастанию, после сортировки будет выполнено условие: a[1] a[2]
a[3]
...
a[N]
В ходе сортировки элементы последовательности меняются местами. Сортировка называется устойчивой, если на этапе замены два одинаковых ключа не меняются местами. Сортировка называется внутренней, если все сортируемые ключи размещаются в оперативной памяти. Если некоторая часть ключей размещается на внешнем носителе, то сортировка называется внешней. Сортировку массивов принято называть внутренней в отличие от сортировки файлов (списков), которую называют внешней. Основное условие при внутренней сортировке массивов – это не вводить дополнительных массивов, т.е. все перестановки элементов должны выполняться «на том же месте» в исходном массиве.
Поиском называется алгоритм, который на входе воспринимает некоторое значение х и определяет запись, ключ которой совпадает со значением х. При этом на выходе такой алгоритм может выдать либо найденную запись, либо указатель на нее. Х называется аргументом поиска.
Если в таблице имеется запись с ключом, равным х, то поиск называется удачным или результативным. В противном случае поиск называется неудачным (безрезультатным).
Методы внутренней сортировки
Существует три категории прямых методов внутренней сортировки (сортировка включением, сортировка выбором, обменная сортировка).
Сортировки включением
Сортировка прямым включением.
Допустим, что массив a[1..n] разбит на две части a1..i-1, ai..n – в первой части элементы упорядочены, во второй – нет. При i=2 такое разбиение получается автоматически, т.к. массив из одного элемента тривиально упорядочен. На каждом шаге i=2..n выполняем элементарный алгоритм: берем очередной элемент r из неупорядоченной части и включаем его в «нужное» место упорядоченной части. Для поиска нужного места в нижеприведенном алгоритме используется барьер a[0]:=x. Элементы, начиная от i-1 до нужного j сдвигаются на одну позицию: a[j]:=a[j-1]. На каждом проходе происходит перемещение i -того элемента в готовую последовательность, а некоторое число элементов сдвигается вправо. Данный процесс перемещения называется просачиванием элемента.
Во всех процедурах сортировки ключи упорядочиваются по возрастанию. На входе процедур - количество элементов массива ( n ), на выходе - упорядоченный массив элементов (а).
Procedure Straight_Insertion(n:integer; Var a:array[1..100] of integer);
Var i,j:word;
X,r:integer;
Begin
For i:=2 To n Do
Begin
x:=a[i];r:=a[i]; a[0]:=x; j:=i;
While x<a[j-1] Do
Begin a[j]:=a[j-1]; j:=j-1; end;
a[j]:=r
end;
End;{ Straight_Insertion}{сортировка прямым включением}
Сортировка бинарными включениями.
Алгоритм сортировки прямыми включениями можно легко улучшить, пользуясь тем, что готовая последовательность a[1],...,a[i-1], в которую нужно включить новый элемент, уже упорядочена. Поэтому место включения можно найти значительно быстрее, применив бинарный поиск, который исследует средний элемент готовой последовательности и продолжает деление пополам, пока не будет найдено место включения. Модифицированный алгоритм сортировки называется сортировкой бинарными включениями.
Procedure Binary_Insertion(n:word;Var a: array[1..100] of integer);
Var i,j,l,r,m:word;
x:integer;
Begin
For i:=2 To n Do
Begin
x:=a[i]; l:=1; r:=i-1;
While l<=r Do
Begin
m:=(l+r) div 2;
If x < a[m] 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;{Binary_Insertion}{сортировка бинарным вкючением}
Сортировка выбором
Прямой выбор.
Для i=1..n-1 выполняется следующий элементарный алгоритм: среди элементов ai..n выбираем минимальный am и переставляем местами элементы i -й и m -й. В результате на первое место станет самый минимальный, на второе – следующий минимальный и т.д.
Procedure Straight_Selection(n:word;Var a array[1..100] of integer);
Var i,j,k:word;
x:integer;
Begin
For i:=1 To n-1 Do
Begin
m:=i;
For j:=i+1 To n Do
If a[m] > a[j] Then m:=j;
x:=a[i]; a[i]:=a[m]; a[m]:=x
End
End;{Straight_Selection} {сортировка простым выбором}
Обменные сортировки
Сортировка прямого обмена (пузырьковая).
Это метод, в котором обмен двух элементов является основной характеристикой процесса. Алгоритм сортировки простым обменом основан на принципе сравнения и обмена пары соседних элементов до тех пор, пока не будут рассортированы все элементы. Для i=1..n-1 выполняется следующий элементарный алгоритм: начиная от n до i последовательно проверяем упорядоченность двух соседних элементов a[j] и a[j-1], и если они не упорядочены, то меняем их местами. В результате такого обмена минимальный элемент перемещается на место i.
Критерием окончания является отсутствие обменов при очередном проходе.
Во всех процедурах сортировки ключи упорядочиваются по возрастанию. На входе процедур - количество элементов массива ( n ), на выходе - упорядоченный массив элементов (а).
Procedure Bubble_Sort(n:word;Var a: array[1..100] of integer);
Var i,j:word;
x:integer;
Begin
For i:=1 To n-1 Do
Begin
For j:=n DownTo i Do
If a[j-1]>a[j] Then
Begin
x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x
End
End
End;{Bubble_Sort}
Шейкерная сортировка.
Улучшение алгоритма - это запоминать, производится ли на данном проходе какой-либо обмен. Если нет, то это означает, что алгоритм может закончить работу. Этот процесс улучшения можно продолжить, если запомнить не только сам факт обмена, но и место (индекс) последнего обмена.
Однако внимательный программист заметит здесь странную асимметрию: один неправильно расположенный "пузырек" в "тяжелом" конце рассортированного массива всплывет на место за один проход, а неправильно расположенный элемент в "легком" конце будет опускаться на правильное место только на один шаг на каждом проходе. Изменение направления сортировки в каждом из проходов алгоритма поиска называют шейкерной сортировкой.
Для того чтобы тяжелые элементы сразу попадали вниз, пузырьковую сортировку выполняют так, чтобы направление прохода было снизу вверх, следующий проход - сверху вниз и так далее.
Procedure Shaker_Sort(n:word;Var a:array [1..100] of integer);
Var j,k,l,r:word;
x:integer;
Begin
l:=2; r:=n; k:=n;
Repeat
For j:=r DownTo l Do {проход снизу-вверх}
If a[j-1]>a[j] Then
Begin
x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x; k:=j;
end;
l:=k+1;
For j:=l To r Do {проход cверху-вниз}
If a[j-1]>a[j] Then
Begin
x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x; k:=j;
end;
r:=k-1;
Until l>r
End;{Shaker_Sort}
Пирамидальная сортировка.
Предположим, что дана пирамида с элементами hl+1,..., hr для некоторых значений l и r и нужно добавить новый элемент x для того, чтобы сформировать расширенную пирамиду hl,..., hr. Новый элемент x сначала помещается в вершину дерева, а затем “просеивается” по пути, на котором находятся меньшие по сравнению с ним элементы, которые одновременно поднимаются вверх; таким образом, формируется новая пирамида.
В процедуре Heap_Sort вызывается процедура Sift, которая реализует алгоритм формирования пирамиды.
Procedure Heap_Sort(n:word;Var a: array [1..100] of integer);
Var l,r:word;x:integer;
Procedure Sift;
Label 13;
Var i,j:word;
Begin
i:=l; j:=2*i; x:=a[i];
While j<=r Do
Begin
If j<r Then
If a[j]<a[j+1] Then j:=j+1;
If x>=a[j] Then Goto 13;
a[i]:=a[j]; i:=j; j:=2*i;
end;
13: a[i]:=x
End;{Sift}
BEGIN
l:=(n div 2)+1; r:=n;
While l>1 Do
Begin
l:=l-1; Sift
end;
While r>1 Do
Begin
x:=a[1]; a[1]:=a[r]; a[r]:=x;
r:=r-1; Sift
End
END;{Heap_Sort}
Обменная сортировка разделением (быстрая сортировка).
Выбирается любой произвольный элемент массива, далее массив просматривается слева направо до тех пор пока не будет найден элемент больший выбранного; а затем просмотрим его справа налево, пока не найдем элемент меньший выбранного. Найденные элементы поменяем местами. Затем продолжим процесс “просмотра с обменом”, пока два просмотра не встретятся где-то в середине массива. В результате массив разделится на две части: левую - с ключами меньшими выбранного элемента; и правую - с большими ключами. Описанный алгоритм применяется к обоим этим частям, в результате чего последовательность разбивается на 4 части. Алгоритм применяется к каждой четвертинке и т.д. Разделение заканчивается, когда в каждой части остается 1 элемент.
В процедуре Quick_Sort вызывается процедура Sort, которая реализует алгоритм разделения и обмена для одной части массива.
Procedure Quick_Sort(n:word;Var a:massiv);
Procedure Sort(l,r:word);
Var w,x:integer;
i,j:word;
Begin
i:=l; j:=r;
x:=a[(l+r) div 2];
Repeat
While a[i]<x Do i:=i+1;
While a[j]>x Do j:=j-1;
If i<=j Then
Begin
w:=a[i]; a[i]:=a[j]; a[j]:=w;
i:=i+1; j:=j-1
End
Until i>j;
If l<j Then Sort(l,j);
If i<r Then Sort(i,r);
End;{Sort}
BEGIN
Sort(1,n);
END;{Quick_Sort}
Контрольные вопросы
- Дайте определение понятиям «поиск» и «сортировка».
- Что такое ключ и основные требования к нему?
- Назовите принципы действия сортировки включением. Приведите примеры.
- Назовите принципы действия сортировки выбором.
- Назовите принципы действия обменной сортировки. Приведите примеры.