- •СТРУКТУРЫ ДАННЫХ И АЛГОРИТМЫ
- •Глава 1 Линейные списки
- •Понятие структуры данных
- •Тип указатель
- •Линейный список
- •Линейный однонаправленный (односвязный) список
- •Линейный двунаправленный (двусвязный) список
- •Практическое задание «Линейные списки»
- •Задачи для самостоятельной работы
- •Контрольные вопросы
- •Глава 2 Структуры данных стек и очередь
- •Понятие структуры данных стек и очередь
- •Структура данных стек
- •Структура данных очередь
- •Пример решения задачи с использованием стека
- •Практическое задание «Стеки и очереди»
- •Задачи для самостоятельной работы
- •Контрольные вопросы
- •Глава 3 Древовидные структуры данных
- •Понятие структуры данных дерево
- •Представление структуры бинарное дерево в памяти
- •Обход дерева
- •Основные операции над деревом
- •Ввод дерева
- •Практическое задание «Бинарные деревья»
- •Задачи для самостоятельной работы
- •Контрольные вопросы
- •Глава 4 Структура данных таблица
- •Понятие структуры данных таблица
- •Представление таблицы в памяти
- •Организация хеш-таблиц
- •Выбор функции расстановки
- •Разрешение коллизии
- •Операции над таблицами
- •Практическое задание «Управление таблицами»
- •Задачи для самостоятельной работы
- •Контрольные вопросы
- •Глава 5 Алгоритмы упорядочения данных
- •Понятие операции упорядочения
- •Алгоритмы упорядочения
- •Сортировка слиянием
- •Основные алгоритмы сортировки посредством сравнений
- •Улучшенные алгоритмы сортировки сравнением
- •Практическое задание «Алгоритмы сортировки»
- •Задачи для самостоятельной работы
- •Контрольные вопросы
- •Библиографический список
Для определения дерева как единой структуры, нужно задать указатель на корень дерева:
tree *t;
Для инициализации дерева достаточно указателю t присвоить значение NULL:
t = NULL;
На рис. 3.3 представлено двоичное динамическое дерево d в соответствии с определением типа элемента, сделанным выше. Элементы дерева со степенью 0 и 1 имеют два или одно ссылочное поле со значением равным пустому указателю (NULL).
Обход дерева
Обрабатывая дерево, приходится просматривать его элементы – эта операция называется обходом дерева (или прохождение дерева).
Обход дерева – это способ методичного исследования его узлов, при котором каждый узел проходится точно один раз. Полное прохождение динамического дерева дает линейную расстановку его узлов.
d
NULL
NULL |
|
NULL |
|
NULL |
|
NULL |
|
|
|
NULL |
NULL NULL
Рис. 3.3
71
Возможны два способа прохождения бинарного дерева (если дерево не пусто) – в глубину и в ширину:
а) в глубину:
– прямой (префиксный) порядок: корень, левое поддерево в прямом порядке, правое поддерево в прямом порядке (линейная расстановка узлов дерева, представленного на рис. 3.1, б: ABDCEGFHJ);
Алгоритм прямого обхода:
PREORDER(tree *t)
{
stack s = NULL; while (t != NULL)
{
PROCESS(d);
if (t->left != NULL && t->right != NULL)
{
PUSH(S, t->right); t = t->left;
}
else
if (t->left == NULL && t->right == NULL) if (s != NULL)
POP(s, t); else
t = NULL;
else
t = t->left != NULL ? t->left : t->right;
}
}
Рекурсивное описание алгоритма прямого обхода:
PREORDER(tree *t)
72
{
if (t != NULL)
{
PROCESS(t); PREORDER(t->left); PREORDER(t->right);
}
}
– обратный (инфиксный) порядок: левое поддерево в обратном порядке, корень, правое поддерево в обратном порядке (линейная расстановка узлов дерева, представленного на рис. 3.1, б: DBAEGCHFJ);
Алгоритм обратного обхода:
PREORDER(tree *t)
{
stack s = NULL;
for (char f = 1; f; )
{
while (t != NULL)
{
PUSH(s, t); t = t->left;
}
if (s != NULL)
{
POP(s, t); PROCESS(t); t = t-right;
}
else
f = 0;
}
}
73
Рекурсивное описание алгоритма обратного обхода:
INORDER(tree *t)
{
if (t != NULL)
{
INORDER(t->left); PROCESS(t); INORDER(t->right);
}
}
– концевой (постфиксный) порядок: левое поддерево в концевом порядке, правое поддерево в концевом порядке, корень (линейная расстановка узлов дерева, представленного на рис. 3.1.б: DBGEHJFCA);
Алгоритм концевого обхода:
POSTORDER(tree *t)
{
stack s = NULL; do
{
while (t != NULL)
{
PUSH(s, t, 0); t = t->left;
}
if (s != NULL)
{
do {
POP(s, t, f); if (f)
PROCESS(t);
} while (f && s != NULL);
74
if (!f)
{
PUSH(s, t, 1); t = t->right;
}
} while (s != NULL);
}
Рекурсивное описание алгоритма концевого обхода:
POSTORDER(tree *t)
{
if (t != NULL)
{
POSTORDER(t->left);
POSTORDER(t->right); PROCESS(t);
}
}
б) в ширину: узлы дерева посещаются слева направо, уровень за уровнем вниз от корня (линейная расстановка узлов дерева, представленного на рис. 3.1, б: ABCDEFGHJ).
Алгоритм обхода в ширину:
LEVELORDER(tree *t)
{
queue q = NULL; if (t != NULL)
{
PUSH(q, d); do {
POP(q, t); PROCESS(t);
75
