- •Предисловие
- •Основы программирования
- •Понятие алгоритма.
- •Алгоритм Евклида.
- •Задача о поездах и мухе
- •Вместо лирического отступления
- •Этапы подготовки задачи для решения на компьютере
- •Примеры разработки алгоритмов
- •Решение квадратного уравнения.
- •Вычисление интегралов
- •Обработка результатов эксперимента
- •Решение системы линейных алгебраических уравнений
- •Введение в язык программирования 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 Типовые алгоритмы обработки информации
____________________________________________________________________
Процедура находится в модуле OutScr}
output_to_screen(name_file);
if n= -1 then
writeln(UTF8ToConsole('Такого менеджера нет'))
else
writeln(UTF8ToConsole('Менеджер найден, его номер '),
n+1);
write(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
4.2.2 Вставка и удаление элементов в упорядоченном массиве
Часто бывает необходимо вставлять новые элементы в упорядоченный массив, а также удалять элементы из массива. Такие задачи часто возникают в системах управления базами данных, где пользователи вводят большое количе-
ство данных. "Приличная" система должна давать пользователям возможность корректирования введенных данных, т.е. вставки новых данных, изменения уже введенных данных и удаления данных. Задача эта не столь тривиальна, как мо-
жет показаться на первый взгляд. Пусть необходимо вставить новый элемент x
в упорядоченный по возрастанию массив a[1..n] в место с номером k, где k<n.
Если просто присвоить a[k]:= x;
то элемент с индексом k, который находился там ранее, будет потерян.
Следовательно, предварительно необходимо сдвинуть все элементы a[k], a[k+1], …, a[n] на одну позицию вправо. Это можно сделать с помощью цикла:
for i:= n downto k do
a[i+1]:= a[i];
323
4.2 Алгоритмы поиска
____________________________________________________________________
inc(n);
То же самое при удалении элемента из массива. Если удаляется элемент a[k], то все оставшиеся элементы a[k+1], …, a[n] надо сдвинуть на одну пози-
цию влево, чтобы закрыть возникшую "дыру" в k-й позиции массива.
Код для сдвига элементов массива при удалении элемента a[k] будет та-
ким:
for i:= k + 1 to n do
a[i-1]:= a[i];
dec(n);
Напишем программу вставки нового элемента в массив. Предположим, что массив состоит из целых чисел 1, 2, 3, 4. Моделируем ситуацию, когда пользо-
ватель при вводе массива допустил ошибку, пропустил число 3. Поскольку оператор readln "не реагирует" на ввод пустой строки, была введена следую-
щая последовательность чисел: 1, 2, 4, 5. Необходимо дать пользователю воз-
можность откорректировать данные, введенные им в массив.
program project1; uses
CRT, FileUtil; var
i, n: integer;
a: array of integer; NewElement: integer; IndexOfNewElement: integer; SizeOfArray: integer; answ: char;
324
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
begin
writeln(UTF8ToConsole('Введите размер массива')); readln(SizeOfArray);
SetLength(a, SizeOfArray); writeln(UTF8ToConsole('Введите элементы массива')); for i:= 0 to SizeOfArray - 1 do
read(a[i]); writeln(UTF8ToConsole('Введен массив:')); for i:= 0 to SizeOfArray - 1 do write(a[i], ' '); writeln;
writeln(UTF8ToConsole('Откорректируйте данные')); writeln(UTF8ToConsole('Если все правильно, нажмите Enter,')); writeln(UTF8ToConsole('иначе - любую клавишу'));
answ:= readkey;
if answ = #13 then exit; writeln(UTF8ToConsole('Введите новый элемент')); readln(NewElement); writeln(UTF8ToConsole('Введите индекс в массиве,'));
writeln(UTF8ToConsole('куда нужно вставить новый элемент')); readln(IndexOfNewElement);
for i:= SizeOfArray - 1 downto IndexOfNewElement do a[i+1]:= a[i];
a[IndexOfNewElement]:= NewElement;
if IndexOfNewElement= SizeOfArray then inc(SizeOfArray);
writeln(UTF8ToConsole('Массив после вставки нового элемента'));
for i:= 0 to SizeOfArray - 1 do
write(a[i], ' '); writeln;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
325
4.2 Алгоритмы поиска
____________________________________________________________________
readkey;
end.
Как всегда, ищем возможность улучшения программы. В предыдущей про-
грамме пользователь сам вводил индекс в массиве, куда нужно вставить новый элемент. Оказывается, алгоритм бинарного поиска позволяет автоматически вставлять новый элемент в нужное место. Каким образом? Рассмотрим на кон-
кретном примере. Пусть имеется массив из 5 элементов. Необходимо вставить число 3. Вспомним алгоритм бинарного поиска. Первоначальное расположение
указателей будет, так как показано на рисунке 4.12. |
|
|||
1 |
2 |
4 |
5 |
6 |
left |
|
middle |
|
right |
|
Рис. 4.12. Начальное расположение указателей |
При этом значения переменных будут равны:
key = 3, left = 0 (не забывайте, нумерация в динамических массивах с нуля!) right = 4, middle = (left+right) div 2 = (0 + 4) div 2 = 2
a[middle] = a[2] = 4
key = 3 < a[2] = 4, т.е. значение ключа меньше значения среднего элемента.
Согласно алгоритму, переменной right будет присвоено значение:
right = middle - 1 = 2 - 1 = 1
middle = (left+right) div 2 = (0 + 1) div 2 = 1
Новое расположение указателей показано на рисунке 4.13.
1 2 4 5 6
left middle right
Рис. 4.13. Новое расположение указателей
326
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
a[middle] = a[1] = 2
key = 3 > a[1] = 2, т.е. значение ключа больше значения среднего элемента,
следовательно, переменной left будет присвоено значение left = middle + 1 = 1 + 1 = 2
Значение left оказывается больше right: left = 2 > right = 1
Алгоритм поиска заканчивает свою работу, искомый элемент не найден.
Но, посмотрите чему равно значение left. Оно равно 2, т.е. как раз тому индексу
вмассиве, куда должен быть помещен новый элемент, т.е. key равный 3!
Валгоритме достаточно изменить один оператор, в том месте, где функция
BinarySearch возвращает -1 (элемент не найден!), т.е. вместо
BinarySearch:= -1;
необходимо записать
BinarySearch:= left;
Итак, улучшенная программа предыдущего примера. В этой программе вставка нового элемента оформлена в виде процедуры. Кроме того, введены проверки на правильность ввода размера массива
program modify_insert;
uses
CRT, FileUtil;
var
i: integer;
a: array of integer;
NewElement: integer;
327
4.2 Алгоритмы поиска
____________________________________________________________________
IndexOfNewElement: integer; SizeOfArray: integer; answ: char;
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:= left;
end;
procedure insert_new_element(var a: array of integer;
var NewElement: integer; var IndexOfNewElement: integer); begin
for i:= SizeOfArray - 1 downto IndexOfNewElement do
328
Глава 4 Типовые алгоритмы обработки информации
____________________________________________________________________
a[i + 1]:= a[i];
a[IndexOfNewElement]:= NewElement;
if IndexOfNewElement= SizeOfArray then
inc(SizeOfArray);
end;
begin
writeln(UTF8ToConsole('Введите размер массива')); while true do
begin readln(SizeOfArray); if SizeOfArray = 0 then begin
writeln(UTF8ToConsole('Размер массива не может быть = 0')); writeln(UTF8ToConsole('Введите размер массива'));
end else
if SizeOfArray < 0 then begin
writeln(UTF8ToConsole('Размер массива не может быть < 0')); writeln(UTF8ToConsole('Введите размер массива'));
end
else break; end;
SetLength(a, SizeOfArray); writeln(UTF8ToConsole('Введите элементы массива')); for i:= 0 to SizeOfArray - 1 do
read(a[i]); writeln(UTF8ToConsole('Введен массив:')); for i:= 0 to SizeOfArray - 1 do
329
4.2 Алгоритмы поиска
____________________________________________________________________
write(a[i], ' '); writeln; writeln(UTF8ToConsole('Откорректируйте данные')); writeln(UTF8ToConsole('Если все правильно, нажмите Enter,')); writeln(UTF8ToConsole('иначе - любую клавишу'));
answ:= readkey;
if answ = #13 then exit; writeln(UTF8ToConsole('Введите новый элемент')); readln(NewElement);
IndexOfNewElement:= BinarySearch(a, NewElement); insert_new_element(a, NewElement, IndexOfNewElement);
writeln(UTF8ToConsole('Массив после вставки нового элемента'));
for i:= 0 to SizeOfArray - 1 do
write(a[i], ' '); writeln;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
В программе предполагается, что первоначальный размер массива не дол-
жен изменяться. Если вы помните, в примере мы моделировали ситуацию, ко-
гда пользователю необходимо было откорректировать ошибочно введенные данные. Если же вам нужно, чтобы вставляемый элемент расширял исходный массив, вам нужно в процедуре insert_new_element заменить условный оператор
if IndexOfNewElement = SizeOfArray then inc(SizeOfArray);
на просто оператор инкремента
330