- •Предисловие
- •Основы программирования
- •Понятие алгоритма.
- •Алгоритм Евклида.
- •Задача о поездах и мухе
- •Вместо лирического отступления
- •Этапы подготовки задачи для решения на компьютере
- •Примеры разработки алгоритмов
- •Решение квадратного уравнения.
- •Вычисление интегралов
- •Обработка результатов эксперимента
- •Решение системы линейных алгебраических уравнений
- •Введение в язык программирования Pascal
- •Основные элементы языка
- •Переменные. Стандартные типы.
- •Операции отношения
- •Раздел описаний переменных
- •Выражения. Порядок выполнения операций.
- •Константы
- •Комментарии в программе
- •Операторы
- •2.1.7.1. Оператор присваивания
- •2.1.7.2. Операторы ввода/вывода
- •2.1.7.3. Операторы инкремента и декремента
- •Среда разработки Lazarus
- •Русский язык в консольных приложениях
- •Первая программа
- •Открытие существующего проекта
- •Другие способы создания консольных приложений
- •Типовой пустой проект
- •Операции с целыми числами
- •Вместо лирического отступления 2
- •Стандартные функции с целыми аргументами
- •Операции с вещественными числами (тип real).
- •Форматирование вывода
- •Одновременное использование вещественных и целых чисел.
- •Другие стандартные функции с вещественными аргументами
- •Булевы переменные
- •Условные операторы.
- •2.1.22.1 Оператор if …. then
- •2.1.22.2. Оператор if …then ... else
- •Операторы цикла
- •2.1.23.1. Оператор цикла с предусловием
- •2.1.23.2. Оператор цикла с постусловием
- •2.1.23.3. Оператор цикла с параметром.
- •2.1.23.4. Второй вариант оператора цикла с параметром
- •Оператор выбора case
- •Организация простейшего контроля ввода данных.
- •Вычисление сумм сходящихся рядов
- •Реализация некоторых алгоритмов главы 1.
- •Программа решения задачи о поездах и мухе
- •Программа вычисления определенного интеграла
- •Более сложные элементы языка
- •Общая структура Паскаль – программы
- •Процедуры и функции
- •3.1.1.1 Структура процедуры
- •3.1.1.2. Структура функции
- •3.1.1.3 Глобальные и локальные переменные
- •3.1.1.4 Способы передачи параметров
- •3.1.1.5 Процедуры завершения
- •Еще раз о типах данных
- •Классификация типов данных
- •3.2.1.1 Целый тип
- •3.2.1.2. Интервальный тип
- •3.2.1.3. Перечислимый тип
- •3.2.1.4. Множества
- •3.2.1.5. Логический тип
- •3.2.1.6. Вещественный тип
- •3.2.1.7. Указатели
- •Обработка символьной информации в Паскале
- •Символьные и строковые типы данных.
- •3.3.1.1. Тип Char
- •3.3.1.2. Функции для работы с символами
- •3.3.1.3. Тип String
- •3.3.1.4. Строковые процедуры и функции
- •Массивы
- •Динамические массивы
- •Программа решения системы линейных алгебраических уравнений методом Гаусса
- •3.4.1.1. Вариант 1 – с goto
- •3.4.1.2. Вариант 2 – без goto
- •3.4.1.3. Вариант 3 – наилучшая реализация
- •Модули в Паскале
- •Структура модуля
- •Системные модули
- •3.5.2.1. Модуль CRT
- •Файлы
- •Тип данных – запись
- •Файловые типы
- •Процедуры для работы с файлами
- •3.6.3.1. Общие процедуры для работы с файлами всех типов
- •3.6.3.2. Процедуры для работы с текстовыми файлами
- •3.6.3.3. Процедуры для работы с типизированными файлами
- •3.6.3.4. Процедуры для работы с нетипизированными файлами
- •3.6.3.5. Организация контроля ввода/вывода при работе файлами
- •3.6.3.6. Создание простой базы данных с типизированными файлами.
- •Алгоритмы сортировки
- •Обменная сортировка (метод "пузырька")
- •Сортировка выбором
- •Сортировка вставками
- •Метод быстрой сортировки
- •Алгоритмы поиска
- •Поиск в массивах
- •Вставка и удаление элементов в упорядоченном массиве
- •Динамические структуры данных
- •Представление в памяти компьютера динамических структур.
- •Реализация стека с помощью массивов
- •Указатели
- •Стандартные операции с линейными списками
- •Реализация динамических структур линейными списками
- •4.3.6.1. Реализация стека
- •4.3.6.2. Реализация очереди с помощью линейного списка
- •4.3.6.3. Реализация двоичного дерева с помощью линейного списка
- •Сортировка и поиск с помощью двоичного дерева
- •Три источника и три составные части ООП.
- •Классы и объекты.
- •Обращение к членам класса.
- •Инкапсуляция
- •Спецификаторы доступа.
- •Свойства.
- •Наследование
- •Полиморфизм
- •Раннее связывание.
- •Позднее связывание.
- •Конструкторы и деструкторы.
- •Элементы графического интерфейса
- •Различия между консольными и графическими приложениями
- •Визуальное программирование в среде Lazarus
- •Создание графического приложения
- •Форма и ее основные свойства
- •Компоненты
- •Обработчики событий
- •Простейшие компоненты
- •6.3.5.1. Компонент TLabel
- •6.3.5.2. Кнопки TButton, TBitBtn и TSpeedButton
- •6.3.6.1. Компонент TEdit
- •6.3.6.2. Компонент TLabeledEdit
- •6.3.7.1. Компонент TMaskEdit
- •Специальные компоненты для ввода чисел
- •Тестирование и отладка программы
- •Компоненты отображения и выбора данных
- •6.3.10.1. Компонент TMemo
- •6.3.10.2. Компонент TStringGrid
- •6.3.10.3. Компоненты выбора
- •Компонент TListBox
- •Компонент TComboBox
- •Компоненты выбора – переключатели
- •6.3.10.4. Компоненты отображения структурированных данных
- •Компонент TTreeView
- •Компонент TListView
- •Организация меню. Механизм действий - Actions
- •6.3.11.1. Компонент TMainMenu
- •6.3.11.2. Компонент TToolBar
- •6.3.11.3. Компонент TActionList
- •6.3.11.4. Создание приложений с изменяемыми размерами окон
- •Послесловие
- •Литература
- •Алфавитный указатель
4.1 Алгоритмы сортировки
____________________________________________________________________
str[j+1]:= v;
end;
end;
begin
str:= 'dkfhytcba';
writeln(UTF8ToConsole('Исходная строка: '),
UTF8ToConsole(str));
insert(str);
writeln(UTF8ToConsole('Отсортированная строка: '),
UTF8ToConsole(str));
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
В качестве упражнения напишите программы сортировки строки с кирил-
лицей, массива строк и файла менеджеров улучшенным методом вставок.
Как и предыдущие алгоритмы, сортировка методом вставок принадлежит классу O(n2). Если же список частично отсортирован, алгоритм метода вставок работает очень быстро и имеет порядок O(n). Немаловажно и то, что алгоритм является устойчивым.
4.1.4 Метод быстрой сортировки
Алгоритм быстрой сортировки был разработан К. Хоаром в 1960 году.
Быструю сортировку называют еще сортировкой с разделением или просто ал-
горитмом сортировки Хоара. Суть метода заключается в следующем: выбира-
ется какой-нибудь элемент списка, называемый базовым или опорным. После этого сортируемый список делится на две части: в левую помещаются все эле-
менты меньшие базового элемента, в правую элементы, большие базового эле-
300
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
мента, а сам базовый элемент при этом окажется на нужном месте в списке. Да-
лее полученные два списка сортируются таким же образом, т.е. вновь выбира-
ются базовые элементы (уже внутри подсписков), подсписки делятся на два, в
левую помещаются элементы меньшие базового элемента, в правую элементы,
большие базового элемента и т.д. При реализации алгоритма процедура, вы-
полняющая основные действия по сортировке вызывает саму себя. Такой вызов функции или процедуры самой себя называется рекурсией. Рассмотрим алго-
ритм подробнее.
Сначала поговорим о выборе базового элемента. Идеальным случаем было бы выбор в качестве базового элемента среднего по значению элемента списка.
Но для этого нужно предварительно просмотреть весь список, вычислить сред-
нее значение, затем снова просмотреть весь список – имеется ли это среднее значение среди элементов списка и все это рекурсивно! По количеству опера-
ций это равносильно самой сортировке.
Если в качестве базового выбирать минимальный или максимальный эле-
мент списка, то, во-первых, для этого все равно нужен предварительный про-
смотр всего списка (подсписков в дальнейшем), во-вторых, что еще хуже, при разделении списка на два, один из подсписков окажется пустым, поскольку все элементы списка будут находиться по одну сторону от базового. При числе элементов списка n, будут выполнены n рекурсивных вызовов. При большом числе n может не хватить стековой памяти, к тому же алгоритм может просто зациклиться.
Не вдаваясь в дальнейшие тонкости, скажем, что чаще всего в качестве ба-
зового элемента берут элемент средний по месту нахождения элемента в спи-
ске. Итак, алгоритм:
Заводятся два указателя (индекса) i и j. В начале i 1 и j n , где n -
число сортируемых записей.
На каждом шаге выполняется разбиение записей на две подгруппы так,
чтобы
301
4.1 Алгоритмы сортировки
____________________________________________________________________
левая подгруппа |
правая подгруппа |
||
--------------- |
---------------- |
||
Ri |
Rbase |
R j |
Rbase |
Ri , R j - |
текущие записи (элементы); |
Rbase - базовый элемент рассматри- |
ваемой группы из n записей (элементов). Имеются два внутренних цикла. Пер-
вый цикл делает просмотр элементов правой подгруппы справа. |
Сравнивают- |
ся Rbase с Rj , j n, n 1, , до тех пор, пока не встретится |
R j < Rbase . Затем |
второй внутренний цикл выполняет просмотр элементов левой подгруппы сле-
ва. Сравниваются Rbase с Ri , i 1,2, до тех пор, пока не встретится Ri > Rbase .
Теперь возможны два случая:
1. i < j, это означает, что два элемента, на которые указывают индексы
расположены в неправильном порядке. Действительно, элемент, который нахо-
дится в левом подсписке больше, чем базовый элемент, а элемент, который на-
ходится в правом подсписке, меньше базового элемента.
Меняем местами элементы и продолжаем выполнение внутренних циклов.
2. i >= j, это означает, что текущая подгруппа успешно разделена. Выпол-
нение внутренних циклов завершается.
Внешний цикл начинает свою работу вновь с определения базового эле-
мента, теперь уже для текущей подгруппы.
Теоретические расчеты эффективности метода показывают в среднем n log2 (n) операций сравнений.
Напишем программу быстрой сортировки для массива с произвольным числом элементов. В качестве элементов возьмем целые числа.
program quick_sort;
uses
CRT, FileUtil;
302
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
type
vector= array of integer; var
i, n: integer;
sorted_array: vector; // сортируемый массив
{ ============= Метод быстpой сортировки ======== }
procedure QuickSort(var sorted_array: vector); { rec_sort - рекурсивная процедура }
procedure rec_sort(first, last: integer;
var sorted_array: vector);
{ first, last - первый и последний элементы текущей группы } var
i: integer; // указатель для левого списка j: integer; // указатель для правого списка middle: integer; // средний элемент списка temp: integer;
begin
while (first < last) do begin
middle:= sorted_array[(first + last) div 2]; i:= pred(first);
j:= succ(last); while true do begin
repeat dec(j);
until sorted_array[j] <= middle; repeat inc(i);
303
4.1 Алгоритмы сортировки
____________________________________________________________________
until sorted_array[i] >= middle; if i >= j then break;
temp:= sorted_array[i]; sorted_array[i]:= sorted_array[j]; sorted_array[j]:= temp;
end;
{рекурсивный вызов процедуры}
if first < j then rec_sort(first, j, sorted_array);
first:= succ(j);
end;
end;
{ ======= конец процедуры rec_sort ======== }
begin
{ первый вызов рекурсивной процедуры} rec_sort(0, n - 1, sorted_array);
end;
{ ======= конец процедуры QuickSort ======== }
begin
writeln(UTF8ToConsole('Введите количество элементов массива')); readln(n);
SetLength(sorted_array, n); writeln(UTF8ToConsole('Введите элементы массива')); for i:= 0 to n - 1 do
read(sorted_array[i]); QuickSort(sorted_array); writeln(UTF8ToConsole('Отсортированный массив:')); writeln;
304
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
for i:= 0 to n - 1 do
write(sorted_array[i], ' ');
writeln;
writeln;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
В программе использованы функции pred() и succ().
Функция succ увеличивает (инкрементирует) значение порядковой пере-
менной. Можно инкрементировать:
Символы;
Невещественные числовые типы;
Тип перечисления;
Указатели.
Функция pred уменьшает значение порядковой переменной.
Выше мы неоднократно отмечали, что один и тот же алгоритм можно реа-
лизовывать по разному. Вот пример другой реализации того же алгоритма.
program quick_sort;
uses
CRT, FileUtil;
type
vector= array of integer;
var
i, n: integer;
sorted_array: vector; // сортируемый массив
305
4.1 Алгоритмы сортировки
____________________________________________________________________
{ ============ Метод быстpой сортировки ======= }
procedure QuickSort(var sorted_array: vector); { rec_sort - рекурсивная процедура }
procedure rec_sort(first, last: integer;
var sorted_array: vector);
{ first, last - первый и последний элементы текущей группы }
var
i: integer; // указатель для левого списка
j: integer; // указатель для правого списка
middle: integer; // средний элемент списка temp: integer;
begin
i:= first; // первый элемент текущего списка j:= last; // последний элемент текущего списка
middle:= sorted_array[(first + last) div 2]; repeat
while sorted_array[i] < middle do i:= i + 1;
while middle < sorted_array[j] do j:= j - 1;
if i <= j then begin
temp:= sorted_array[i]; sorted_array[i]:= sorted_array[j]; sorted_array[j]:= temp;
i:= i + 1; j:= j - 1;
end;
306
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
until i > j;
{рекурсивные вызовы процедуры для левых и правых подсписков}
if first < j then rec_sort(first, j, sorted_array);
if i < last then rec_sort(i, last, sorted_array);
end;
{ ==================================================== }
begin
{первый вызов рекурсивной процедуры} rec_sort(0, n - 1, sorted_array);
end;
{=======================================}
begin
writeln(UTF8ToConsole('Введите количество элементов массива')); readln(n);
SetLength(sorted_array, n); writeln(UTF8ToConsole('Введите элементы массива')); for i:= 0 to n - 1 do
read(sorted_array[i]); QuickSort(sorted_array); writeln(UTF8ToConsole('Отсортированный массив:')); writeln;
for i:= 0 to n - 1 do write(sorted_array[i], ' ');
writeln;
writeln;
writeln(UTF8ToConsole('Нажмите любую клавишу')); readkey;
end.
307
4.1 Алгоритмы сортировки
____________________________________________________________________
Напишем программу сортировка файла алгоритмом Хоара.
program quick_sort_file; uses
CRT, FileUtil, SysUtils, OutScr; type
manager= record name: string[18]; comp: integer; end;
var
company: manager;
f_not_sorted, f_sorted: File of manager; vector: array of manager;
i, n: integer; name_file: string;
{ ========= Метод быстpой сортировки ======== }
procedure QuickSort(var sorted_array: array of manager);
{ rec_sort - рекурсивная процедура } procedure rec_sort(first, last: integer;
var sorted_array: array of manager);
{ first, last |
- первый и последний элементы текущей группы } |
var |
|
i: integer; // указатель для левого списка |
|
j: integer; |
// указатель для правого списка |
308
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
middle: manager; // средний элемент списка temp: manager;
begin
while (first < last) do begin
middle:= sorted_array[(first + last) div 2]; i:= Pred(first);
j:= Succ(last); while true do begin
repeat dec(j);
until sorted_array[j].name <= middle.name; repeat inc(i);
until sorted_array[i].name >= middle.name; if i >= j then break;
temp:= sorted_array[i]; sorted_array[i]:= sorted_array[j]; sorted_array[j]:= temp;
end;
{рекурсивный вызов процедуры}
if first < j then rec_sort(first, j, sorted_array); first:= Succ(j);
end;
end;
{ ======================================= } begin
{первый вызов рекурсивной процедуры}
rec_sort(0, n - 1, sorted_array);
end;
309
4.1 Алгоритмы сортировки
____________________________________________________________________
begin
{При необходимости укажите полный путь к файлу
или скопируйте файл в папку с данным проектом}
if not FileExists('File_not_sorted.dat') then
begin
writeln(UTF8ToConsole('Файлы не существуют'));
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;
QuickSort(vector); // вызов процедуры быстрой сортировки
CloseFile(f_not_sorted);
AssignFile(f_sorted, 'File_sorted.dat');
310
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
Rewrite(f_sorted); for i:= 0 to n - 1 do
Write(f_sorted, vector[i]); CloseFile(f_sorted); name_file:= 'File_sorted.dat';
{Вызов процедуры для вывода на экран сводной ведомости.
Процедура находится в модуле OutScr}
output_to_screen(name_file);
write(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Резюмируя все вышесказанное относительно методов сортировки можно сказать, что наиболее часто используются метод вставок и алгоритм быстрой сортировки Хоара. Что касается других алгоритмов сортировки, то вы можете их найти в специальной литературе [9, 10, 12].
311