Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
osnovy_programmirovanija_v_srede_lazarus.pdf
Скачиваний:
185
Добавлен:
18.03.2015
Размер:
6.53 Mб
Скачать

4.1 Алгоритмы сортировки

____________________________________________________________________

на

if vector[j].comp < vector[min].comp then min:= j;

4.1.3 Сортировка вставками

Алгоритм этого метода следующий: берем первые два элемента и распола-

гаем их в правильном порядке. Затем берем следующий элемент и вставляем его в нужное место среди тех, что мы уже обработали. Рассматриваемый эле-

мент вставляется в позицию посредством передвижения большего элемента на одну позицию вправо и затем размещением меньшего элемента в освободив-

шуюся позицию. На каждом шаге i элемент a[i] помещается в подходящую по-

зицию среди элементов a[1], ..., a[i-1]. Теперь элементы a[1], ..., a[i] являются упорядоченными, но не "совсем", поскольку среди оставшихся элементов a[i+1], ..., a[n] на каком-нибудь k-м шаге может найтись элемент меньший, чем a[1], ..., a[i], a[i+1], … a[k-1] и он будет вставлен в подходящее место среди этих элементов. Процесс завершится когда последний n-й элемент будет поме-

щен в подходящее для него место. Проиллюстрируем сказанное:

4

3

2

1

Рис. 4.8 Исходный массив

3

4

2

1

Рис. 4.9 Шаг первый, меняются первые два элемента

3

2

4

1

2

3

4

1

Рис. 4.10 Шаг второй, элемент "2" занял свое место, при этом "3" и "4" сдвинулись вправо.

286

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

2

3

1

4

2

1

3

4

1

2

3

4

Рис. 4.11 Шаг третий, элемент "1" занял свое место, при этом "2", "3" и "4" сдвинулись вправо.

Алгоритм будет содержать два цикла. Во внешнем цикле указатель i будет двигаться направо ( увеличиваться) начиная с 2, до n, где n количество элемен-

тов. Во внутреннем цикле указатель j сдвигается влево начиная с i-1. На каждом шаге j-м шаге происходит сдвиг элементов вправо до тех пор, пока a[i] не ока-

жется меньше a[j]. Тогда a[i] останется на этом месте и внутренний цикл за-

вершится. Внутренний цикл также может завершиться, когда будет достигнуто начало списка. Рассмотрим программу сортировки строки символов по алфави-

ту методом вставок:

program insertion_sort_string;

uses

CRT, FileUtil;

var

str: string;

{Процедура сортировки методом вставок}

procedure insert(var str: string);

var

i, j: integer;

v: char;

begin

for i:= 2 to Length(str) do

287

4.1 Алгоритмы сортировки

____________________________________________________________________

begin

v:= str[i]; j:= i - 1;

{Условие выхода из цикла: найдено подходящее место

для текущего элемента или достигнуто начало строки}

while (str[j] > v) and (j > 0) do begin

str[j+1]:= str[j]; dec(j);

end; str[j+1]:= v;

end;

end;

begin

str:= 'hgfedcba';

writeln(UTF8ToConsole('Исходная строка: '),

UTF8ToConsole(str));

insert(str);

writeln(UTF8ToConsole('Отсортированная строка: '),

UTF8ToConsole(str));

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

В этой программе мы рассматривали строку как массив символов. Для строки, состоящей из символов кириллицы, алгоритм необходимо несколько видоизменить. Внешний цикл будет начинаться с 3, так как в кодировке UTF-8

первый байт второго символа строки будет иметь номер 3.

288

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

program insertion_sort_string;

uses

CRT, FileUtil;

var

str: string;

{Процедура сортировки методом вставок кириллицы}

procedure insert_kyr(var str: string); var

i, j: integer; v, v1: string[2];

begin

for i:= 3 to Length(str) do begin

v:= Copy( str, i, 2); j:= i - 2;

{Условие выхода из цикла: найдено подходящее место

для текущего элемента или достигнуто начало строки}

while (Copy(str, j, 2) > v) and (j > 0) do begin

v1:= Copy(str, j, 2); str[j+2]:= v1[1]; str[j+3]:= v1[2]; dec(j, 2);

end;

str[j+2]:= v[1]; str[j+3]:= v[2];

end;

end;

289

4.1 Алгоритмы сортировки

____________________________________________________________________

begin

str:= 'зжедгвба';

writeln(UTF8ToConsole('Исходная строка: '),

UTF8ToConsole(str));

insert_kyr(str);

writeln(UTF8ToConsole('Отсортированная строка: '),

UTF8ToConsole(str));

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

Что будет, если строка "смешанная"? Т.е. содержит и символы кириллицы и символы латиницы. Проще всего поступить следующим образом. Просмот-

реть всю строку и сформировать две новые строки. Одна будет содержать толь-

ко кириллицу, а другая только латиницу. Затем "скормить" процедуре insert_kyr

строку с кириллицей, процедуре insert строку с латиницей. И в завершение объ-

единить отсортированные строки функцией Concat.

program insertion_sort_string;

uses

CRT, FileUtil;

var

str, str_lat, str_kyr: string;

i: integer;

{Процедура сортировки методом вставок латиницы}

procedure insert(var str: string);

var

i, j: integer;

290

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

v: char;

begin

for i:= 2 to Length(str) do

begin

v:= str[i]; j:= i - 1;

{Условие выхода из цикла: найдено подходящее место

для текущего элемента или достигнуто начало строки}

while (str[j] > v) and (j > 0) do

begin

str[j+1]:= str[j];

dec(j);

end;

str[j+1]:= v;

end;

end;

{Процедура сортировки методом вставок кириллицы}

procedure insert_kyr(var str: string); var

i, j: integer; v, v1: string[2];

begin

for i:= 3 to Length(str) do begin

v:= Copy( str, i, 2); j:= i - 2;

{Условие выхода из цикла: найдено подходящее место

для текущего элемента или достигнуто начало строки}

while (Copy(str, j, 2) > v) and (j > 0) do

291

4.1 Алгоритмы сортировки

____________________________________________________________________

begin

v1:= Copy(str, j, 2); str[j+2]:= v1[1]; str[j+3]:= v1[2]; dec(j, 2);

end;

str[j+2]:= v[1]; str[j+3]:= v[2];

end;

end;

begin

str:= 'зжедгвбаhgfedcbaиклмнijklmn'; i:= 1;

str_lat:= ''; str_kyr:= '';

while i <= Length(str) do begin

if ord(str[i]) < 128 then

begin

str_lat:= str_lat + str[i]; inc(i);

end else begin

str_kyr:= str_kyr + Copy(str, i, 2); inc(i, 2);

end;

292

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

end;

writeln(UTF8ToConsole('Исходная строка: '),

UTF8ToConsole(str));

insert(str_lat); // сортировка латиницы insert_kyr(str_kyr); // сортировка кириллицы

str:= Concat(str_lat, str_kyr);

writeln(UTF8ToConsole('Отсортированная строка: '),

UTF8ToConsole(str));

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

Напишем программу сортировки массива строк методом вставок. В про-

грамме строки сортируются по первому символу строки. Например, если задан массив из 4 строк:

Яковлев

Петров

Сидоров

Алексеев

то программа выдаст массив в следующем виде:

Алексеев

Петров

Сидоров

Яковлев

293

4.1 Алгоритмы сортировки

____________________________________________________________________

program insertion_sort_array;

uses

CRT, FileUtil;

var

str: array of string;

i, n: integer;

{Процедура сортировки методом вставок}

procedure insert(var str: array of string); var

i, j: integer; stroka: string;

begin

for i:= 1 to High(str) do begin

stroka:= str[i]; j:= i - 1;

while (str[j][1] > stroka[1]) and (j >= 0) do begin

str[j+1]:= str[j]; dec(j);

end;

str[j+1]:= stroka; end;

end;

begin

writeln(UTF8ToConsole('Введите количество строк в массиве')); readln(n);

SetLength(str, n);

294

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

writeln(UTF8ToConsole('Введите '), n); writeln(UTF8ToConsole('строк(и) символов'));

for i:= 0 to n - 1 do

readln(str[i]);

writeln(UTF8ToConsole('Исходный массив строк'));

for i:= 0 to n - 1 do

writeln(str[i]);

insert(str);

writeln(UTF8ToConsole('Отсортированный массив строк: '));

for i:= 0 to n - 1 do

writeln(str[i]);

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

Отсортируем массив менеджеров (раздел 3.6.3.3. и 4.1.2) методом вставок:

program insertion_sort_file; uses

CRT, SysUtils, OutScr, FileUtil; type

manager= record name: string[18]; comp: integer; end;

var

company: manager;

f_not_sorted, f_sorted: File of manager; vector: array of manager;

295

4.1 Алгоритмы сортировки

____________________________________________________________________

i, n: integer;

name_file: string;

{Процедура сортировки методом вставок файла по фамилиям менеджеров} procedure insert(var vector: array of manager);

var

i, j, count: integer; t: manager;

begin

count:= high(vector); for i:= 0 to count do begin

t:= vector[i]; j:= i - 1;

while (vector[j].name > t.name) and (j >= 0) do begin

vector[j + 1] := vector[j]; dec(j);

end;

vector[j + 1] := t; end;

end;

{ ================================================ } begin

{При необходимости укажите полный путь к файлу

или скопируйте файл в папку с данным проектом}

if not FileExists('File_not_sorted.dat') then

begin

writeln(UTF8ToConsole('Файлы не существуют'));

296

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

writeln(UTF8ToConsole('Сначала создайте их'));

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

exit;

end;

AssignFile(f_not_sorted,'File_not_sorted.dat');

Reset(f_not_sorted);

// Определение количества записей в файле

n:= System.FileSize(f_not_sorted);

SetLength(vector, n);

{Подготовка к внутренней сортировке,

считывание записей файла в массив,

в процедуру передается массив, а не файл.}

i:= 0;

while not Eof(f_not_sorted) do begin

Read(f_not_sorted, company); vector[i]:= company; // сортируемый массив i:= i + 1;

end;

insert(vector); // вызов процедуры сортировки методом вставок

CloseFile(f_not_sorted);

AssignFile(f_sorted, 'File_sorted.dat');

Rewrite(f_sorted);

for i:= 0 to n - 1 do Write(f_sorted, vector[i]); CloseFile(f_sorted); name_file:= 'File_sorted.dat';

{Вызов процедуры для вывода на экран сводной ведомости.

297

4.1 Алгоритмы сортировки

____________________________________________________________________

Процедура находится в модуле OutScr}

output_to_screen(name_file);

write(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

Во внутреннем цикле метода вставок осуществляется две проверки. Одна для нахождения подходящего места текущему элементу, а другая (j>0, если нумерация индексов начинается с 1 и j>=0, если нумерация индексов начина-

ется с 0) для предотвращения выхода за пределы левого края массива (строку символов можно рассматривать как массив, элементами которого являются от-

дельные символы строки).

Однако эта дополнительная проверка, как показывают многочисленные эксперименты, замедляют работу алгоритма почти до 7%. Выходом из этой си-

туации является помещение в первый элемент массива так называемого "сто-

рожевого" элемента, который являлся бы минимальным элементом массива. Но заранее (до начала работы алгоритма) значение минимального элемента, как правило, неизвестно. Следовательно, необходимо предварительно просмотреть весь массив, найти минимальный элемент и переместить его в начало массива

(фактически это выполнение первого цикла сортировки методом выбора). Те-

перь, когда первый элемент уже находится в требуемой позиции, можно запус-

кать алгоритм сортировки методом вставок без проверки на выход за пределы начала массива. Программа для улучшенного метода вставок выглядит сле-

дующим образом:

program modify_insertion_sort_string;

uses

CRT, FileUtil;

var

298

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

str: string;

{Процедура, реализующая улучшенный алгоритм

сортировки методом вставок}

procedure insert(var str:string);

var

i, j: integer;

v: char;

min: integer;

begin

{Поиск минимального элемента в строке}

min:= 1;

for i:= 2 to length(str) do

if str[i] < str[min] then min:= i;

{Меняем местами найденный символ с первым

символом в строке}

v:= str[1];

str[1]:= str[min];

str[min]:= v;

{Реализация собственно метода вставок}

for i:= 2 to length(str) do

begin

v:= str[i]; j:= i - 1;

// теперь в цикле проверяется только одно условие

while str[j] > v do

begin

str[j+1]:= str[j];

dec(j);

end;

299

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]