- •Предисловие
- •Основы программирования
- •Понятие алгоритма.
- •Алгоритм Евклида.
- •Задача о поездах и мухе
- •Вместо лирического отступления
- •Этапы подготовки задачи для решения на компьютере
- •Примеры разработки алгоритмов
- •Решение квадратного уравнения.
- •Вычисление интегралов
- •Обработка результатов эксперимента
- •Решение системы линейных алгебраических уравнений
- •Введение в язык программирования 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.2 Алгоритмы поиска
____________________________________________________________________
4.2. Алгоритмы поиска
Поиск каких-либо данных, наряду с сортировкой, является одной из наи-
более распространенных задач при разработке сколько-нибудь сложных про-
граммных проектов, в частности при разработке информационно-поисковых и информационно-справочных систем. В любой базе данных присутствуют зада-
чи сортировки и поиска. Алгоритмы поиска являются не менее сложными и ин-
тересными, чем алгоритмы сортировки.
Рассмотрим некоторые алгоритмы поиска в массивах.
4.2.1 Поиск в массивах
Пусть нам дан какой-нибудь массив. Требуется найти элемент массива по заданному ключу. Первое, что приходит на ум, чтобы решить эту задачу, это последовательно сравнивать элементы массива с заданным ключом, пока не бу-
дет найден искомый элемент. Если элемент найден, алгоритм должен выдать номер индекса этого элемента в массиве. Если же такого элемента в массиве нет, то алгоритм должен нам каким-то образом сообщить об этом. Чаще всего в таком случае алгоритм возвращает значение, которого заведомо нет в массиве,
а точнее такого индекса. Такой алгоритм называется алгоритмом линейного по-
иска. Напишем соответствующую функцию в предположении, что поиск ведет-
ся в массиве целых чисел.
function LinearSearch(var a: array of integer;
key: integer): integer;
var
i: integer;
begin
312
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
for i:= 0 to High(a) do
begin
if key = a[i] then
begin
LinearSearch:= i;
exit;
end;
end;
LinearSearch:= -1;
end;
Итак, эта функция возвращает нам номер индекса в массиве, где находится искомый элемент. Возвращать само значение не имеет смысла, мы и так его знаем (значение key). В случае отсутствия искомого элемента функция воз-
вращает -1. Обратите внимание, в самом массиве может быть и есть элемент со значением -1, но функция возвращает индекс элемента в массиве. Как мы зна-
ем, индекс не может быть отрицательным, возврат -1 и говорит нам о том, что искомого элемента в массиве нет.
Программа линейного поиска для целочисленного массива:
program search_in_array; uses
CRT, FileUtil; const SizeOfFile= 9; var
a:array[0..SizeOfFile] of integer = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); n: integer;
key: integer;
313
4.2 Алгоритмы поиска
____________________________________________________________________
{ ============= Линейный поиск ======== } function LinearSearch(var a:array of integer;
key: integer): integer;
var
i: integer; begin
for i:=0 to SizeOfFile do begin
if key = a[i] then begin
LinearSearch := i; exit;
end;
end; LinearSearch:= -1; end;
{ ======================================== }
begin
writeln(UTF8ToConsole('Введите ключ для поиска')); readln(key);
{вызов функции поиска}
n:= LinearSearch(a, key);
if n= -1 then
writeln(UTF8ToConsole('Такого элемента в массиве нет'))
else
writeln(UTF8ToConsole('Элемент найден, его номер в массиве '),
n);
write(UTF8ToConsole('Нажмите любую клавишу'));
314
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
readkey;
end.
Напишем программу поиска менеджера по фамилии. Для удобства провер-
ки результатов работы программы, одновременно выводится весь файл менед-
жеров и указывается номер искомой записи.
program search_in_file; uses
CRT, FileUtil, SysUtils, OutScr; type
manager= record name: string[18]; comp: integer;
end; var
company: manager;
f_not_sorted: File of manager; // Файловая переменная vector: array of manager;
i, n: integer; name_file: string; name_manager: string;
{ ========= Линейный поиск ======== } function LinearSearch(var not_sorted_array:
array of manager; name_manager: string): integer;
var
i: integer;
315
4.2 Алгоритмы поиска
____________________________________________________________________
begin
for i:= 0 to High(not_sorted_array) do begin
if name_manager = not_sorted_array[i].name then begin
LinearSearch := i; exit;
end;
end; LinearSearch:= -1; end;
{ ================================== }
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);
316
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
{Подготовка поиску,
считывание записей файла в массив,
в функцию передается массив, а не файл.}
i:= 0;
while not Eof(f_not_sorted) do begin
Read(f_not_sorted, company);
vector[i]:= company; // массив, в которым будет вестись поиск i:= i + 1;
end; CloseFile(f_not_sorted);
writeln(UTF8ToConsole('Введите фамилию менеджера')); readln(name_manager);
{вызов функции поиска}
n:= LinearSearch(vector, name_manager);
name_file:= 'File_not_sorted.dat';
{Вызов процедуры для вывода на экран списка менеджеров.
Процедура находится в модуле OutScr}
output_to_screen(name_file);
if n= -1 then
writeln(UTF8ToConsole('Такого менеджера нет'))
else
writeln(UTF8ToConsole('Менеджер найден, его номер '),
n+1);
write(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Очевидно, что время поиска по этому алгоритму зависит от размера масси-
317
4.2 Алгоритмы поиска
____________________________________________________________________
ва – количества его элементов n. Т.е. этот алгоритм принадлежит классу O(n).
Если массив неупорядочен, то единственный способ найти какой-либо элемент, это линейный поиск. Если же массив упорядочен, то существуют бо-
лее быстрые и эффективные алгоритмы. Наиболее часто используемым являет-
ся алгоритм двоичного (бинарного) поиска. Его также часто называют метод деления пополам.
Суть метода в том, что, пользуясь тем, что массив отсортирован, вместо просмотра подряд всех элементов массива, находим элемент, находящийся по-
середине массива. Назовем его средним элементом (не по значению, а по месту в массиве). Затем сравниваем искомый элемент с этим средним элементом. Ес-
ли искомый элемент меньше среднего, то искать теперь его следует только сре-
ди тех, которые меньше среднего. Таким образом, диапазон поиска уменьшает-
ся ровно наполовину. Берем ту половину массива, где следует искать наш эле-
мент и опять находим средний элемент, опять его сравниваем с искомым эле-
ментом и вновь суживаем зону поиска наполовину и т.д. продолжаем процесс до тех пор, пока в рассматриваемых подмассивах не останется один элемент.
Если он равен искомому, значит элемент найден, если не равен, значит такого элемента в массиве нет.
При выполнении алгоритма в каждом следующем цикле размер массива уменьшается в два раза, отсюда оценка скорости работы алгоритма O(log2n).
Напишем программу бинарного поиска в массиве целых чисел:
program search_in_array; {$mode objfpc}{$H+} uses
CRT, FileUtil; const SizeOfFile= 9; var
a: array[0..SizeOfFile] of integer =
318
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); n: integer;
key: integer;
{ ======== Бинарный поиск ======== }
function BinarySearch(var a: array of integer; key: integer): integer;
var
left, right, middle: integer; begin
left:= Low(a); right:= High(a); repeat
middle:= (left + right) div 2; if key < a[middle] then
right:= middle - 1 else
if key > a[middle] then left:= middle + 1
else begin
BinarySearch:= middle; exit;
end;
until left > right; BinarySearch:= -1;
end;
{ ========================================== }
319
4.2 Алгоритмы поиска
____________________________________________________________________
begin
writeln(UTF8ToConsole('Введите ключ для поиска'));
readln(key);
{вызов функции поиска}
n:= BinarySearch(a, key);
if n= -1 then
writeln(UTF8ToConsole('Такого элемента в массиве нет'))
else
writeln(UTF8ToConsole('Элемент найден, его номер '), n); writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Напишем программу поиска в файле менеджеров по фамилии бинарным методом:
program search_in_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;
320
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
name_file: string; name_manager: string;
{ ======= Бинарный поиск ======== }
function BinarySearch(var a: array of manager; name_manager: string): integer;
var
left, right, middle: integer; begin
left:= Low(a); right:= High(a); repeat
middle:= (left + right) div 2;
if name_manager < a[middle].name then right:= middle - 1
else
if name_manager > a[middle].name then left:= middle + 1
else begin
BinarySearch:= middle; exit;
end;
until left > right; BinarySearch:= -1;
end;
{ ========================================= } begin
{При необходимости укажите полный путь к файлу
или скопируйте файл в папку с данным проектом}
321
4.2 Алгоритмы поиска
____________________________________________________________________
if not FileExists('File_not_sorted.dat') then
begin
writeln(UTF8ToConsole('Файл не существует'));
writeln(UTF8ToConsole('Сначала создайте его'));
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
exit;
end;
AssignFile(f_sorted,'File_sorted.dat');
Reset(f_sorted);
n:= System.FileSize(f_sorted);
SetLength(vector, n);
{Подготовка к поиску,
считывание записей файла в массив,
в функцию передается массив, а не файл.}
i:= 0;
while not Eof(f_sorted) do begin
Read(f_sorted, company);
vector[i]:= company; // массив, который будет сортироваться i:= i + 1;
end; CloseFile(f_sorted);
writeln(UTF8ToConsole('Введите фамилию менеджера')); readln(name_manager);
{вызов функции поиска}
n:= BinarySearch(vector, name_manager);
name_file:= 'File_sorted.dat';
{Вызов процедуры для вывода на экран сводной ведомости.
322