
Лекция 10
6.4. Простейшие алгоритмы
6.4.1. Поиск
6.4.1.1. Линейный поиск
В массиве A: array[iMin..iMax] of ТИП найти элемент равный B.
Листинг. Алгоритм линейного поиска
i:=iMin;
while (i<iMax) and (A[i]<>B) do i:=i+1;
Цикл while завершит свою работу либо при нахождении элемента равного B, либо при переборе всех элементов массива.
На каждом шаге цикла выполняется две проверки. Для упрощения проверок в конец массива A: array[iMin..iMax+1] of ТИП добавляется барьер - элемент равный B.
Листинг. Алгоритм линейного поиска с барьером
i:=iMin; A[iMax+1]:=B;
while A[i]<>B do i:=i+1;
Завершение работы цикла гарантировано, т.к. элемент B в массиве всегда есть. Ожидаемое число шагов – N/2.
6.4.1.2. Поиск делением пополам
В упорядоченном массиве A: array[iMin..iMax] of ТИП найти элемент равный B.
Листинг. Алгоритм поиска деления пополам
A1:=iMin; A2:=iMax; Ok:=false;
while (A1<=A2) and not Ok do
begin
m:=(A1+A2) div 2;
if A[m]=B then Ok:=true
else
if A[m]<B then A1:=m+1 else A2:=m-1;
end;
Листинг. Упрощенный алгоритм поиска деления пополам
A1:=iMin; A2:=iMax;
while A1<A2 do begin
m:=(A1+A2) div 2;
if A[m]=B then begin
A1:=m; A2:=m;
end
else
if A[m]<B then A1:=m+1 else A2:=m;
end;
Завершение работы цикла гарантировано, т.к. A1<m<A2, A1 – увеличивается, A2 - уменьшается. Ожидаемое число шагов – logN.
6.4.1.3. Поиск в массиве строк
В массиве упорядоченных строк AStr: array[iMin..iMax] of string найти строку St: string.
Воспользуемся поиском деления пополам:
Листинг. Поиск в массиве строк
A1:=iMin; A2:=iMax;
while A1<A2 do
begin
m:=(A1+A2) div 2; i:=0;
while (AStr[m,i]=St[i]) and (St[i]<>#0) do i:=i+1;
if AStr[m,i]<St[i] then A1:=m+1 else A2:=m;
end;
if A2<iMax then begin
i:=0;
while (AStr[A2,i]=St[i]) and (St[i]<>#0) do i:=i+1;
end;
6.4.1.4. Прямой поиск строки
В строке s: string[N] найти строку s0: string[M].
Листинг. Прямой поиск строки
i:=0;
repeat
i:=i+1; j:=1;
while (j<M) and (s[i+j-1]=s0[j]) do j:=j+1;
until (j=M) or (i=N-M);
6.4.2. Сортировка
6.4.2.1. Пузырьковая сортировка
Отсортировать массив A: array[iMin..iMax] of ТИП.
Листинг. Пузурьковая сортировка.
for i:=iMin+1 to iMax do
for j:=iMax downto i do
if A[j-1]<A[j] then
begin
t:=A[j-1]; A[j-1]:=A[j]; A[j]:=t;
end;
6.4.2.2. Шейкерная сортировка
Оптимизация предыдущего алгоритма включает в себя следующее:
массив можно считать уже упорядоченным, если на последнем проходе не было ни одной перестановки элементов;
сравнение пар элементов можно производить только до места последней перестановки: раз не было перестановок, значит – дальше элементы упорядочены;
при прохождении массива слева направо (снизу вверх) поднимается легкий пузырек. Почему бы не двигаться по массиву в обратном направлении – сверху вниз, опуская тяжелый пузырек?
Эти моменты учтены в шейкер-сортировке (от англ. shake – трясти), приведенной в листинге 7.6.
Листинг. Шейкерная сортировка.
procedure SortShaker;
var
j,L,left,right: integer;
tmp : integer;
last : integer; // место последней перестановки
begin
L:=Length(A);
left:=1; right:=L-1; last:=L-1;
repeat
for j:=right downto left do //поднимаются легкие пузырьки
if a[j-1]>a[j] then begin
tmp:=a[j]; a[j]:=a[j-1]; a[j-1]:=tmp;
last:=j
end;
left:=last+1; // запомнили место последней перестановки
for j:=left to right do //опускаются тяжелые пузырьки
if a[j-1]>a[j] then begin
tmp:=a[j]; a[j]:=a[j-1]; a[j-1]:=tmp;
last:=j
end;
right:=last-1; // запомнили место последней перестановки
until left>right;
end; //Shaker