- •Этапы создания исполняемой программы
- •Идентификаторы
- •Ключевые слова
- •Комментарии
- •Структура программы
- •Вывод данных
- •Ввод данных
- •Вопросы для самоконтроля
- •Тема 1.1(2). Типы данных. Константы и переменные
- •Основные (стандартные) типы данных
- •Область действия переменных
- •1.3.1. Математические операции
- •1.3.2. Простое присваивание
- •1.3.3. Составное (сложное) присваивание
- •1.3.4. Операция приведения (преобразования) типов
- •1.3.5. Операции отношения
- •1.3.7. Операция sizeof
- •1.3.8. Операция "запятая" (,)
- •1.3.9. Условная операция (?:)
- •1.3.10. Указатель. Определение адреса переменной
- •1.3.11. Директива define
- •1.3.12. Директива include
- •1.3.13. Примеры программ
- •1.3.14. Вопросы для самоконтроля
- •Тема 1.3. Программирование алгоритмов различной структуры
- •Базовые конструкции структурного программирования
- •Операторы ветвления
- •1.4.1. Условный оператор if
- •If (условие) оператор_1; else оператор_2;
- •If (условие) оператор_1;
- •1.4.2. Оператор выбора switch
- •Операторы цикла
- •1.4.3. Оператор while
- •1.4.4. Оператор do...While
- •1.4.5. Оператор for
- •1.4.6. Функция exit(), операторы break, continue, return
- •Стандартные математические функции
- •Тема 1.4. Ввод-вывод данных
- •Функции get() и put()
- •Функция getch()
- •Функция printf
- •Функция sprintf()
- •Тема 1.5. Функции. Локальные и глобальные переменные. Способы передачи данных.
- •1.5.1. Видимость переменных
- •1.5.2. Определение функции
- •1.5.3. Функция main
- •1.5.4. Вызов функции
- •1.5.5. Способы передачи данных
- •1.5.6. Возвращаемые значения функции
- •1.5.7. Использование прототипов функций
- •Тема 1.6(1). Массивы и указатели
- •Объявление массива
- •Доступ к элементам массива
- •Многомерные массивы
- •Указатели
- •Тема 1.6(2). Структуры и строки
- •1.6.1. Структуры
- •1 Способ – по шаблону.
- •2 Способ – при объявлении (описании) шаблона.
- •1.6.2. Способы реализации строк
- •1.6.3. Строковые константы
- •1.6.4. Указатель на символьную строку
- •1.6.5. Массив символов
- •1.6.6. Некоторые функции для работы со строками
- •1.6.7. Некоторые функции проверки и преобразования символов
- •Тема 1.7. Работа с памятью
- •Функция malloc
- •Функция free
- •Операция new
- •Операция delete
- •Тема 1.10. Динамические структуры
- •Разновидности динамических структур
- •Примеры программ (фрагментов программ) для работы с динамическими структурами
Операция delete
Операция delete освобождает память, выделенную операцией new.
Примеры.
Продолжим предыдущий пример, освободим выделенную память:
delete uk_i;
delete uk_d;
delete [ kol_s ] uk_s;
где kol_s – количество символов в строке.
Тема 1.10. Динамические структуры
Цель изучения темы
-
познакомиться с различными динамическими структурами
-
научиться работать с динамическими структурами в языке С++
До сих пор все рассмотренные программы позволяли работать с массивами фиксированной длины, например массив из 100 элементов. В реальной жизни обычно требуется, чтобы программа могла принимать от 50 до нескольких тысяч элементов и при этом экономно использовала ресурсы компьютера. Такие задачи решаются при помощи динамических структур.
Динамические структуры способны увеличиваться и уменьшаться в процессе работы. Должен быть организовать доступ к каждому элементу динамической структуры.
Разновидности динамических структур
Динамические структуры строятся из динамических элементов.
Динамический элемент состоит из двух частей:
-
информационная часть – хранит значение элемента
-
указатели – это адреса одного или нескольких других динамических элементов
В простейшем случае динамический элемент имеет вид:
В данном случае информационная часть состоит из одного поля, которое используется для хранения одного целого числа, указатель – из указателя на один элемент.
Из динамических элементов формируется цепочка. Динамический элемент хранит адрес следующего динамического элемента.
Существует 5 основных видов динамических структур:
-
очередь
-
стек
-
список
-
двунаправленный список
-
дерево
Очередь
Очередь работает по тому же принципу, что и очередь в магазине: "первым пришел, первым ушел". Элементы добавляются в конец очереди, а берутся из начала. Для работы необходимо знать начало и конец очереди.
Указатель у последнего элемента в очереди хранит нулевое значение.
Стек
Стек работает по принципу "первым пришел, последним ушел". Элементы добавляются и берутся с одного конца, который называется вершина стека.
Список
Порядок работы с элементами списка не определен. Можно, например, вставить или убрать элемент из любой части списка.
Может использоваться кольцевой список, в котором соединены начало и конец.
Двунаправленный список
Двунаправленный список формируется из динамических элементов с двумя указателями.
Может использоваться кольцевой список, в котором начало и конец соединены.
Дерево
Дерево состоит из элементов, которые называются узлами или вершинами.
Узлы соединены направленными дугами X->Y (от Х к Y). X называется предшественником (родителем) Y. Y - называется потомком.
Дерево имеет одну вершину, которая не имеет предшественников. Она называется корнем дерева. Вершины, которые не имеют потомков, называются листьями.
Дерево может формироваться из динамических элементов с двумя указателями.
Примеры программ (фрагментов программ) для работы с динамическими структурами
Программа для организации очереди.
Задача. Создание очереди из произвольного количества целых положительных чисел. Признак окончания ввода - отрицательное число.
#include < iostream.h>
#include < conio.h>
/* Описание структурного элемента, info - информационное поле, next -указатель на следующий элемент. */
struct ELEM
{
int info;
ELEM *next;
};
void main()
{
// Указатели на элементы очереди: первый, последний, текущий, старый, новый
ELEM *nach, *tek, *old, *kon, *new_n;
int i=1;
nach=0;
kon=0;
cout << "\n Введите произвольное кол-во целых чисел";
cout << "\n признак окончания ввода - отрицательное число";
// Создается очередь из целых чисел
do
{
// Ввод числа
cout << "\n Введите целое число";
cin >> i;
if (i<=0) break; // Прекращение цикла
// Создание очередного элемента
new_n=new ELEM; /* Выделяется память под новый элемент, адрес выделенной памяти записывается в new_n */
new_n-> info=i; /* Присваивается значение информационному полю нового элемента*/
new_n-> next=0; /* Присваивается значение указателю нового элемента */
if (nach)
{ // Если очередь не пуста, очередной элемент добавляется в конец очереди
kon-> next=new_n;
kon=new_n;
}
else
{
/* Если очередь пуста, начало и конец очереди будут указывать на один и тот же элемент */
nach=new_n;
kon=new_n;
}
}
while (i> 0);
// Пример обработки элементов
// Элементы отображаются на экране и удаляются из очереди
while (nach)
{
old=nach;
cout << "\n элемент "<< nach-> info; // Выводим элемент на экран
nach=nach-> next; // Переходим к следующему элементу очереди
delete old; // Очищаем память, которую занимал первый элемент
}
getch();
}
Фрагмент программы для реализации стека
Задача. Создание стека из элементов 9, 10,... 16.
nach=0; // nach - вершина стека
for (i=9; i<=16; i++)
{
// Создание очередного элемента
new_n=new ELEM;
new_n-> info=i;
if (nach)
{ // Если стек не пуст, очередной элемент добавляется в вершину стека
new_n-> next=nach;
nach=new_n;
}
else
{ // иначе стек будет состоять из одного элемента
new_n-> next=0;
nach=new_n;
}
Программа для реализации упорядоченного двоичного дерева
Двоичное (бинарное) дерево – это дерево, у каждой вершины которого может быть только два потомка.
Двоичное дерево является самым простым видом дерева. В упорядоченном дереве большее значение располагается справа от вершины, а меньшие значения слева от вершины.
Задача. Построить двоичное упорядоченное дерево из чисел 5, 7, 3, 1, 4.
Первый элемент (5) помещается в корень дерева:
Берем следующий элемент (7). Так как 7 больше 5, помещаем его в правую ветвь от 5:
Берем следующий элемент (3). Так как 3 меньше 5, помещаем его в левую ветвь от 5:
Берем следующий элемент (1). Так как 1 меньше 5 и левая ветвь уже существует (элемент 3), будем сравнивать 1 и 3. 1 меньше 3, поэтому помещаем 1 в левую ветвь от 3.
Берем следующий элемент (4). Так как 4 меньше 5 и левая ветвь уже существует (элемент 3), будем сравнивать 4 и 3. 4 больше 3, поэтому помещаем 4 в правую ветвь от 3. В результате получаем бинарное дерево:
Пример программы "Бинарное дерево".
Для создания дерева будут использованы рекурсивные функции:
dob – для добавления элемента,
pech – для печати элемента дерева.
Элемент дерева будет иметь структуру
#include <iostream.h>
struct DEREVO
{
int info;
DEREVO * next_l;
DEREVO * next_r;
};
void dob (DEREVO * tek, int znach); // прототип функции dob
void pech (DEREVO *tek); // прототип функции pech
void main()
{
int i;
DEREVO *nach, *tek, *new_n;
nach=0;
cout << "\n Вводите значения вершин дерева, 0 - признак окончания ввода ";
do
{
cout << "\nВведите значение вершины";
cin >> i;
if (nach)
{ // Если дерево не пусто, вызывается функци dob
dob(nach, i);
}
else
{ // Если дерево пусто создается корень дерева
new_n=new DEREVO;
new_n-> info=i;
new_n-> next_l=0;
new_n-> next_r=0;
nach=new_n;
}
}
while (i);
pech(nach); // Печать
}
/* Рекурсивная функция dob
tek - указатель на текущую вершину дерева,
znach - значение, которое необходимо добавить в дерево.
Функция dob определяет, в какую ветвь нужно добавить новое значение; если znach меньше текущего значения, то производиться добавление в левую ветвь, иначе - в правую ветвь.
Если ветвь нельзя добавить (такая ветвь уже существует), то снова вызывается функция dob. */
void dob (DEREVO * tek, int znach)
{
int i1;
DEREVO *new_n;
i1=tek-> info;
// Если значение текущего элемента дерева меньше нового элемента
if (znach<i1)
{
if (tek-> next_l)
dob (tek->next_l,znach);
else
{
new_n=new DEREVO;
new_n-> info=znach;
new_n-> next_l=0;
new_n-> next_r=0;
tek-> next_l=new_n;
}
}
if (znach>i1)
{
if (tek-> next_r)
dob (tek-> next_r,znach);
else
{
new_n=new DEREVO;
new_n-> info=znach;
new_n-> next_l=0;
new_n-> next_r=0;
tek-> next_r=new_n;
}
}
}
// Рекурсивная функция pech.
void pech (DEREVO *tek)
{
if (tek)
{
pech(tek-> next_l);
cout << "\n\t" << tek-> info;
pech(tek-> next_r);
}
}