
- •СОДЕРЖАНИЕ
- •ПРЕДИСЛОВИЕ
- •ГЛАВА 1. Введение в алгоритмы
- •1.1. Этапы решения задач на ЭВМ
- •1.2. Понятие алгоритма
- •1.3. Свойства алгоритмов
- •1.4. Сложность алгоритма
- •1.7. Пример простейшего линейного процесса
- •1.7. Пример циклического процесса
- •ГЛАВА 2. Базовые средства языка Си
- •2.1. Алфавит языка Си
- •2.2. Лексемы
- •2.3. Идентификаторы и ключевые слова
- •2.4. Комментарии
- •2.5. Простейшая программа
- •2.7. Декларация объектов
- •2.8. Данные целого типа (integer)
- •2.9. Данные символьного типа (char)
- •2.10. Данные вещественного типа (float, double)
- •ГЛАВА 3. Константы в программах
- •3.2. Константы вещественного типа
- •3.4. Строковые константы
- •ГЛАВА 4. Обзор операций
- •4.1. Операции, выражения
- •4.3. Операция присваивания
- •4.4. Сокращенная запись операции присваивания
- •4.7. Операции сравнения
- •4.8. Логические операции
- •4.10. Операция «,» (запятая)
- •ГЛАВА 5. Обзор базовых инструкций языка Си
- •5.2. Стандартные математические функции
- •5.3. Функции вывода данных на дисплей
- •5.4. Функции ввода информации
- •ГЛАВА 6. Составление разветвляющихся алгоритмов
- •6.1. Краткая характеристика операторов языка Си
- •ГЛАВА 7. Составление циклических алгоритмов
- •7.1. Понятие циклического кода
- •7.2. Оператор с предусловием while
- •7.4. Оператор цикла с предусловием и коррекцией for
- •ГЛАВА 8. Операторы и функции передачи управления
- •8.1. Оператор безусловного перехода goto
- •8.2. Операторы continue, break и return
- •8.3. Функции exit и abort
- •Советы по программированию
- •ГЛАВА 9. Указатели
- •9.1. Определение указателей
- •9.2. Операция sizeof
- •9.3. Инициализация указателей
- •9.4. Операции над указателями
- •ГЛАВА 10. Массивы
- •10.1. Понятие массива
- •10.2. Одномерные массивы
- •10.4. Строки как одномерные массивы данных типа char
- •10.5. Указатели на указатели
- •10.8. Работа с динамической памятью
- •10.9. Библиотечные функции
- •10.10. Пример создания одномерного динамического массива
- •ГЛАВА 11. Функции пользователя
- •11.1. Декларация функции
- •11.2. Вызов функции
- •11.3. Передача аргументов в функцию
- •11.4. Операция typedef
- •11.5. Указатели на функции
- •ГЛАВА 12. Классы памяти и область действия объектов
- •ЗАДАНИЕ 4. Обработка массивов
- •Первый уровень сложности
- •Второй уровень сложности
- •ЗАДАНИЕ 5. Функции пользователя
- •Первый уровень сложности
- •Второй уровень сложности
- •12.3. Статические и внешние переменные
- •12.4. Область действия переменных
- •Советы по программированию
- •13.1. Структуры
- •13.5. Вложенные структуры
- •13.6. Массивы структур
- •13.7. Размещение структурных переменных в памяти
- •13.8. Объединения
- •13.9. Перечисления
- •13.10. Битовые поля
- •ГЛАВА 14. Файлы в языке Си
- •14.1. Открытие файла
- •14.2. Закрытие файла
- •14.3. Запись-чтение информации
- •14.5. Дополнительные файловые функции
- •Советы по программированию
- •ЗАДАНИЕ 7. Создание и обработка файлов
- •Первый уровень сложности
- •Второй уровень сложности
- •ГЛАВА 15. Динамические структуры данных
- •15.1. Линейные списки
- •15.2.1. Алгоритм формирования стека
- •15.2.2. Алгоритм извлечения элемента из стека
- •15.2.3. Просмотр стека
- •15.2.4. Алгоритм освобождения памяти, занятой стеком
- •15.2.5. Алгоритм проверки правильности расстановки скобок
- •15.3.1. Формирование очереди
- •15.3.2. Алгоритм удаления первого элемента из очереди
- •15.4. Двунаправленный линейный список
- •15.4.1. Формирование первого элемента
- •15.4.3. Алгоритм просмотра списка
- •15.4.5. Алгоритм удаления элемента в списке по ключу
- •15.5. Нелинейные структуры данных
- •15.5.1. Бинарные деревья
- •15.5.2. Основные алгоритмы работы с бинарным деревом
- •15.5.4. Вставка нового элемента
- •15.6. Построение обратной польской записи
- •15.6.1. Алгоритм, использующий дерево
- •15.6.2. Алгоритм, использующий стек
- •15.6.3. Пример реализации
- •15.7. Понятие хеширования
- •15.7.2. Примеры хеш-функций
- •15.7.3. Схемы хеширования
- •15.7.4. Примеры реализации схем хеширования
- •Вариант 2. Двунаправленные списки
- •ГЛАВА 16. Переход к ООП
- •16.1. Потоковый ввод-вывод
- •16.3. Проблема ввода-вывода кириллицы в среде Visual C++
- •16.4. Операции new и delete
- •16.6. Шаблоны функций
- •Первый уровень сложности
- •Второй уровень сложности
- •6.1. Основные понятия
- •6.3. Примитивы GDI
- •6.5. Получение описателя контекста устройства
- •6.6. Основные инструменты графической подсистемы
- •6.7. Закрашивание пустот
- •6.8. Рисование линий и кривых
- •6.9. Пример изображения графика функции sin
- •6.10. Рисование замкнутых фигур
- •6.11. Функция Polygon и режим закрашивания многоугольника
- •6.13. Управление областями вывода и отсечением
- •ЗАДАНИЕ 11. Создание графических изображений
- •ЛИТЕРАТУРА

13.Четные и нечетные символы меняются местами.
14.Символы, кратные двум по порядку следования, заменяются на
единицы.
15.Символы, кратные двум по порядку следования, заменяются на свой порядковый номер.
ГЛАВА 15. Динамические структуры данных
15.1. Линейные списки
Некоторые задачи исключают использование структур данных
фиксированного размера и требуют |
введения структур, |
способных |
|||||
|
|
|
|
|
|
|
Р |
увеличивать или уменьшать свой размер уже в процессе работы программы. |
|||||||
Основу таких структур составляют динамические переменные. |
|
||||||
|
|
|
|
|
|
И |
|
Динамическая переменная хранится в некоторой области ОП, |
|||||||
обращение к которой производится через переменную-указатель. |
|
||||||
Как правило, |
динамические |
переменные |
|
У |
|
||
организуются в списковые |
|||||||
структуры данных, |
|
|
|
Г |
|
|
|
элементы которых имеют тип struct. Для адресации |
|||||||
элементов в структуру включается ук з тель (адресное поле) |
на область |
||||||
размещения следующего элемента. |
|
Б |
|
|
|
||
|
|
|
|
|
|
||
Такой список называют однон п |
вленным (односвязным). Если |
||||||
добавить в каждый элемент |
ссылрау на |
предыдущий, |
получится |
двунаправленный список (двусвязный), если последний элемент связать |
|
|
к |
указателем с первым, получится кольц вой список. |
|
е |
|
ут |
|
Например, пусть необходимо создать линейный список, содержащий целые числа, тогда каждый элемент списка должен иметь информационную
(infо) часть, в кот р й буд находиться данные, и адресную часть (р), в
которой будут размещаться указатели связей, т.е. элемент такого списка |
||||||
имеет вид |
л |
о |
||||
|
и |
|
|
|||
и |
infо |
p |
|
|||
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
а шаблон структуры будет иметь вид |
||||||
Б |
|
|
|
|
|
|
structбSpis { int info; Spis *p;
} ;
Каждый элемент списка содержит ключ, идентифицирующий этот элемент. Ключ обычно бывает либо целым числом, либо строкой и является частью поля данных. В качестве ключа в процессе работы со списком могут выступать разные части поля данных.
Например, если создается линейный список из записей, содержащих фамилию, год рождения, стаж работы и пол, любая часть записи может выступать в качестве ключа. При упорядочивании такого списка по алфавиту
128

ключом будет являться фамилия, а при поиске, например, ветеранов труда – ключом будет стаж работы. Как правило, ключи должны быть уникальными, но могут и совпадать. В случае совпадения ключей лучше всего использовать схемы организации структур данных по принципам «хеширования».
Над списками можно выполнять следующие операции: |
|
|
|||
– начальное формирование списка (создание первого элемента); |
|||||
– добавление элемента в список; |
|
|
|
|
|
– обработка (чтение, удаление и т.п.) элемента с заданным ключом; |
|||||
– вставка элемента в заданное место списка (до или после элемента с |
|||||
заданным ключом); |
|
|
|
|
Р |
|
|
|
|
|
|
– упорядочивание списка по ключу. |
|
|
|
И |
|
Если программа состоит из функций, решающих вышеперечисленные |
|||||
задачи, то необходимо соблюдать следующие требования: |
|
|
|||
|
|
|
У |
|
|
– все параметры, не изменяемые внутри функций, должны |
|||||
передаваться с модификатором const; |
|
Г |
|
|
|
– указатели, которые могут изменяться, |
передаются по адресу. |
||||
|
Б |
|
|
|
|
Например, при удалении из списка последнего |
элемента, измененный |
указатель на конец списка требует корректировки, т.е. передачи в точку вызова.
прежн й проталкивается вниз и временно становится недоступным. Когда же верхн й элемент удаляется из стека, следующий за ним поднимается вверх и станов тся опять доступным.
|
|
|
|
|
|
15.2. Структура д нных СТЕК |
|
|
|
|||||||||||||
|
Стек – упорядоченный набор д нных, в котором размещение новых |
|||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
а |
|
|
|
||||
элементов и удаление существующих производится только с одного его |
||||||||||||||||||||||
конца, который называют вершинойкаст , т.е. стек – это список с одной |
||||||||||||||||||||||
точкой доступа к его элемен ам. Графич ски это можно изобразить так: |
||||||||||||||||||||||
|
|
begin - вершина с ека |
е |
|
|
|
||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
т |
|
|
. . . |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
infon |
An |
о |
infon-1 |
An-1 |
|
|
|
info1 |
NULL |
|
||||||||
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Стек – структура типа LIFO (Last In, First Out) – последним вошел, |
|||||||||||||||||||||
|
|
|
|
|
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
первым выйдет. Стек получил свое название из-за схожести с оружейным |
||||||||||||||||||||||
магаз |
|
с патронамил |
(обойма): когда в стек добавляется новый элемент, то |
|||||||||||||||||||
|
|
б |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
ином |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Максимальное число элементов стека ограничивается, т.е. по мере |
|
вталкиванияБ |
в стек новых элементов память под него должна динамически |
запрашиваться и освобождаться также динамически при удалении элемента из стека. Таким образом, стек – динамическая структура данных, состоящая из переменного числа элементов одинакового типа.
Состояние стека рассматривается только по отношению к его вершине, а не по отношению к количеству его элементов, т.е. только вершина стека характеризует его состояние.
Операции, выполняемые над стеком, имеют специальные названия:
129
push – добавление элемента в стек (вталкивание);
pop – выталкивание (извлечение) элемента из стека, верхний элемент стека удаляется (не может применяться к пустому стеку).
Кроме этих обязательных операций часто нужно прочитать значение элемента в вершине стека, не извлекая его оттуда. Такая операция получила название peek.
Рассмотрим основные алгоритмы работы со стеком, взяв для простоты в качестве информационной части целые числа, хотя информационная часть может состоять из любого количества объектов допустимого типа, за исключением файлов.
15.2.1. Алгоритм формирования стека |
|
|
|
Р |
||||||||||||||||
Рассмотрим данный алгоритм для первых двух элементов. |
||||||||||||||||||||
|
||||||||||||||||||||
1. Описание структуры переменной, содержащей информационное и |
||||||||||||||||||||
адресное поля: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
И |
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
У |
|
|||||
|
|
|
|
|
|
→ |
|
|
|
|
|
|
|
|
|
|
||||
|
struct Stack |
info |
|
|
|
Next |
|
|
|
|
||||||||||
|
|
|
|
|
|
Г |
|
|
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
Шаблон структуры рекомендуется описыв ть глобально: |
|
|
||||||||||||||||||
|
|
struct Stack { |
|
|
|
|
|
|
|
|
Б |
|
|
|
||||||
|
|
|
|
|
|
int info; |
|
|
|
|
а |
|
|
|
|
|||||
|
|
} ; |
|
|
|
Stack *Next; |
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
к |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
2. Объявление указа ел й на структуру: |
|
|
|
|
||||||||||||||||
|
|
|
|
|
|
|
|
|
е |
|
|
|
|
|
|
|
||||
|
Stack *begin (вершина с ека), *t (текущий элемент); |
|
||||||||||||||||||
3. Так как перв начально с ек пуст: begin = NULL; |
|
|
||||||||||||||||||
4. Захват памя |
|
п д первый (текущий) элемент: |
|
|
|
|||||||||||||||
|
|
|
|
|
|
|
т |
|
|
|
|
или t = new Stack; |
||||||||
|
|
t = (Stack*) malloc (sizeof(Stack)); |
||||||||||||||||||
|
|
|
|
|
о |
|
|
|
|
|
|
|
|
|
|
|
||||
т.е. t равен А1. |
|
ти |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
л |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
формируется конкретный адрес ОП (обозначим его А1) для первого элемента, |
||||||||||||||||||||
5. Ввод информации (например, i1); |
|
|
|
|
|
|||||||||||||||
|
|
а) формирование информационной части: |
|
|
|
|||||||||||||||
|
б |
t -> info = i1; |
|
|
|
|
|
|
|
|
|
|
|
|||||||
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
б) формирование адресной части: значение адреса вершины стека |
||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
записываем в адресную часть текущего элемента (там был NULL) |
||||||||||||||||||||
Б |
|
|
|
t -> Next = begin; |
|
|
|
|
|
|
|
|
||||||||
|
|
t |
→ |
|
info = i1 |
|
Next |
|
|
→ |
begin = NULL |
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6. Вершина стека переносится на созданный первый элемент: begin = t;
в результате получается следующее:
130
|
begin (A1) ® |
info = i1 |
|
NULL |
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
7. Захват памяти под второй элемент: |
|
|
|
|
|
|
|
|||||||||||
|
t = (Stack*) malloc (sizeof(Stack)); |
или t = new Stack; |
|
|||||||||||||||
формируется конкретный адрес ОП (A2) для второго элемента. |
|
|||||||||||||||||
8. Ввод информации для второго элемента (i2); |
|
|
|
|||||||||||||||
|
а) формирование информационной части: |
|
|
|
||||||||||||||
|
|
t -> info = i2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
б) в адресную часть записываем значение адреса вершины, т.е. |
|||||||||||||||||
адрес первого (предыдущего) элемента (А1): |
|
|
|
|
|
|
Р |
|||||||||||
|
|
t -> Next = begin; |
|
|
|
|
|
|
|
|
|
|
И |
|||||
|
t (A2) ® |
info = i2 |
|
Next = A1 |
|
|
У |
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
9. Вершина стека снимается с первого и устанавливается на новый |
||||||||||||||||||
элемент (A2): |
begin = t; |
|
|
|
|
|
|
|
|
|
|
Г |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
Б |
|
|
|
||||||
получается следующая цепочка: |
|
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
begin (A2) ® |
|
|
info = i2 |
Next = A1 |
|
® |
|
|
info = i1 |
Next = NULL |
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
а |
|
|
|
|
|
||||
Обратите внимание, что действия 7, 8, 9 идентичны действиям 4, 5, 6, |
||||||||||||||||||
|
|
|
|
|
|
ме |
|
можно выполнять в цикле, до тех |
||||||||||
т.е. добавление новых элементов в ст |
|
|||||||||||||||||
пор, пока это необходимо. |
т |
ек |
|
|
|
|
|
|
|
|||||||||
Функция формирования эл |
нта стека для объявленного ранее типа |
|||||||||||||||||
данных может выглядеть следующим образом: |
|
|
|
|
|
|
|
|||||||||||
Stack* Create(Stack *begin) { |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
Stack *t = (Stack*)malloc(sizeof(Stack)); |
|
|
|
||||||||||||||
|
printf(“\n Input Info |
”); |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
} л |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
scanf(“%d”,о&t -> info); |
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
t -> Next = begin; |
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
б |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return t; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Участок программы с обращением к функции Create для добавление |
||||||||||||||||||
Б |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
необход мого количества элементов в стек может иметь следующий вид: |
||||||||||||||||||
|
¼ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Stack *begin = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
int repeat = 1; |
|
|
|
// repeat=1 – продолжение ввода данных |
||||||||||||||
while(repeat) |
{ |
|
||||||||||||||||
|
begin = Create(begin); |
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
printf(“ Stop - 0 ”); |
// repeat=0 – конец ввода данных |
||||||||||||||||
|
scanf(“%d”, &repeat); |
|
|
|
|
|
|
|
|
|
|
|
|
}
¼
131