Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Структуры и алгоритмы обработки данных. Сортировка массивов и динамические структуры (90

.pdf
Скачиваний:
2
Добавлен:
15.11.2022
Размер:
676.59 Кб
Скачать

case '4': // удаление элемента из конца списка if (this->last!=NULL) //если не ноль

del_end(); //переход на функцию удаления else // если ноль список пуст

printf("\nСписок пустой!!!");

break;

case '5': // очистка списка

del_clear (); //переход на функцию удаления break;

case '6': // вывод всех элементов

if (this->first!=NULL) //если не ноль add_prohod(this->first); //переход на функцию

else // если ноль список пуст printf("\nСписок пустой!!!");

break;

default: //если значение не совпадает ни с одним из значений exit(1); //закрытие программы

}

}

}

};

void main()

{

deq a; // а-объект для обращения к функциям классов

setlocale(LC_ALL, "Rus"); // включение функции использования русского

языка

a.add_menu(); // переход на функцию меню

}

23

Лабораторная работа № 3

Нелинейные иерархические динамические структуры данных. Двоичные

деревья поиска

Цель работы - овладение практическими навыками организации и мани-

пулирования основными иерархическими динамическими структурами данных -

деревьями.

Для выполнения лабораторной работы необходимо:

1.Изучить:

-объявление и использование динамических переменных и указателей;

-способы организации двоичных деревьев поиска (Binary Search Tree, BST) при помощи указателей;

-правила обхода, добавления и удаления элементов в двоичных деревьях поиска.

2.Разработать программу, реализующую ввод, вывод и основные операции,

применимые для двоичных деревьев поиска.

3.Подготовить демонстрационный пример создания и несколько примеров операций.

4.Подготовить отчет, содержащий:

-титульный лист;

-задание;

-описание правил организации и операций с двоичными деревьями поис-

ка (с примерами);

-блок-схему алгоритмов операций;

-текст программы;

-пример выполнения программы;

-выводы по работе;

-список использованной литературы.

24

1. Задание к работе

Выбрать из табл. 3 (вариант задается преподавателем) тип информацион-

ного поля для двоичного дерева поиска, правило обхода и правило удаления элемента. Реализовать структуру с помощью указателей. Каждый узел дерева,

кроме полей для связи, хранит некоторое значение типа, выбранного в соответ-

ствии с вариантом. Допускается добавление других информационных полей по необходимости. Предусмотреть в программе возможность последовательного ввода или генерации дерева случайным образом с выбранным количеством элементов. Также должны быть реализованы такие функции как добавление,

поиск узла по заданному значению, обход дерева с выводом и удаление узла дерева в соответствии с выбранным вариантом, удаление всей структуры.

Таблица 3

Вариант

Тип

 

Замена

информационного

Обход

удаляемого узла

задания

поля

 

 

 

 

 

 

 

 

 

1

2

3

4

1

Целый

Прямой

Самым правым левого

поддерева

 

 

 

 

 

 

 

2

Вещественный

Обратный

Самым левым правого

поддерева

 

 

 

 

 

 

 

3

Символьный

Симметричный

Самым правым левого

поддерева

 

 

 

 

 

 

 

4

Строка

Прямой

Самым левым правого

поддерева

 

 

 

 

 

 

 

5

Целый

Обратный

Самым правым левого

поддерева

 

 

 

 

 

 

 

6

Вещественный

Симметричный

Самым левым правого

поддерева

 

 

 

 

 

 

 

25

 

 

 

Окончание табл. 3

 

 

 

 

1

2

3

4

7

Символьный

Прямой

Самым правым левого

поддерева

 

 

 

 

 

 

 

8

Строка

Обратный

Самым левым правого

поддерева

 

 

 

 

 

 

 

9

Целый

Симметричный

Самым правым левого

поддерева

 

 

 

 

 

 

 

10

Вещественный

Прямой

Самым левым правого

поддерева

 

 

 

 

 

 

 

11

Символьный

Обратный

Самым правым левого

поддерева

 

 

 

 

 

 

 

12

Строка

Симметричный

Самым левым правого

поддерева

 

 

 

 

 

 

 

13

Вещественный

Прямой

Самым правым левого

поддерева

 

 

 

 

 

 

 

14

Целый

Обратный

Самым левым правого

поддерева

 

 

 

 

 

 

 

15

Вещественный

Симметричный

Самым правым левого

поддерева

 

 

 

 

 

 

 

16

Символьный

Прямой

Самым левым правого

поддерева

 

 

 

 

 

 

 

17

Строка

Обратный

Самым правым левого

поддерева

 

 

 

 

 

 

 

18

Целый

Симметричный

Самым левым правого

поддерева

 

 

 

 

 

 

 

19

Вещественный

Прямой

Самым правым левого

поддерева

 

 

 

 

 

 

 

20

Символьный

Обратный

Самым левым правого

поддерева

 

 

 

 

 

 

 

26

2.Методический пример выполнения работы

Организовать двоичное дерево поиска:

1.Тип информационного поля: целый.

2.Обход дерева: обратный.

3.Удаляемый узел заменяется самым правым узлом левого поддерева.

Описание метода решения задачи

Упорядоченным называется такое дерево, в котором упорядочены все по-

томки каждой вершины. Принято считать, что деревья изображаются так, что-

бы все потомки были упорядочены слева направо. Двоичное (бинарное) дерево можно определить как упорядоченное дерево, каждая вершина которого имеет не более двух потомков, причем каждый из потомков считается либо левым,

либо правым потомком своего родителя.

Деревья поиска – частный вид двоичных деревьев. Каждая вершина имеет некое ключевое поле, позволяющее упорядочить множество вершин. Двоичное дерево называется деревом поиска или поисковым деревом, если для каждой вершины дерева все ключи в ее левом поддереве меньше ключа этой вершины,

а все ключи в ее правом поддереве больше ключа вершины (рис. 3).

Рис. 3. Двоичное дерево поиска

Основными операциями, производимыми с упорядоченным деревом, яв-

ляются: поиск вершины, добавление вершины, удаление вершины, вывод дере-

ва, очистка дерева. Организуются двоичные упорядоченные деревья обычно с

27

помощью указателей (рис. 4).

Рис. 4. Организация двоичного дерева

Обход дерева

Обхода дерева состоит в том, чтобы посетить каждый узел дерева по од-

ному разу, выполняя для каждого узла некоторую операцию. Обратный обход состоит в том, что сначала обходят левое поддерево, затем обходят правое под-

дерево и в конце посещают корень дерева (рис. 5).

Рис. 5. Обратный обход двоичного дерева

Создание дерева

Создается структура Binar_Tree, в которой объявляются переменные: data – вводимые данные, указатели на правое и левое поддеревья Binar_Tree

28

*left, *right.

Добавление элемента

Функция void Add (Binar_Tree **current, int data). Чтобы начать добав-

лять элементы в дерево, нужно проверить текущий элемент. Если он не пустой

(current!=NULL), то проверяется следующее условие: если элемент меньше те-

кущего, то он добавляется в левое поддерево, а если элемент больше текущего,

то в правое поддерево. Если все же current==NULL, то создается функцией new новое дерево Binar_Tree. После данные записываются

(*current)data=data, левому и правому поддеревьям присваиваются значения

NULL.

Функция отображения дерева

Функция void Show (Binar_Tree *current, int l). Чтобы начать просмотр,

нужно проверить текущий элемент: если он не пустой, то просматривается пра-

вое поддерево. Далее начинается цикл, в котором с помощью отступа и вывода данных currentdata элементы будут отображаться на консоли в удобном для просмотра виде. После этого идет просмотр левого поддерева.

Функция полной очистки дерева

Функция void Clear (Binar_Tree **current). Очистка дерева начинается с проверки текущего элемента: если он не равен NULL, то очищаются левые и правые поддеревья, удаляется текущий элемент, счетчик count уменьшается на единицу, и если этот самый счетчик равен нулю, текущему значению присваи-

вается NULL.

Функция обратного обхода дерева

Функция void postorder (Binar_Tree *current). Обратный обход дерева начинается с проверки текущего элемента: если он не равен NULL, то рекур-

сивно обходят левую ветвь, рекурсивно обходят правую ветвь, выводят значе-

ния на консоль.

29

Функция полной генерации дерева

Вводится количество элементов дерева, затем генерируются случайные значения, которые последовательно передаются в функцию добавления элемен-

тов дерева Add(&root, num).

Функция удаления элемента дерева

Функция int Delete (Binar_Tree **current, int data). Удаление элемента дерева начинается с проверки значения в корне дерева. Если корень не равен

NULL и значение в корне не равно удаляемому, нужно найти требуемый эле-

мент в дереве. Если удаляемый элемент меньше корня дерева, рекурсивно об-

ходят левую ветвь дерева, если удаляемый элемент больше корня дерева рекур-

сивно обходят правую ветвь. Когда нужный элемент найден и он является лис-

том (ссылки на левое и правое поддерево равны NULL), он просто удаляется.

Если удаляемый узел имеет одно поддерево, заменяют ссылку в родительском узле ссылкой на дочерний узел удаляемого узла и найденный узел удаляется. В

третьем случае (удаляемый узел имеет два поддерева) выполняется переход на функцию замены void Changer(Binar_Tree **current, Binar_Tree **tmp) и

удаляемый узел заменяется крайним правым из левого дочернего узла.

Функция заполнения дерева

Циклически передаются значения в функцию добавления в дерево

Add(&root, num).

Реализация двоичного дерева поиска и манипуляции с ним

#include <iostream> #include "conio.h"

struct Binar_Tree //объявление структуры дерева

{

int data; //поле

Binar_Tree *left, *right; //указатели лево и право

};

Binar_Tree *root=NULL; //указателю корня присваиваем значение ноль int countt=0; //счетчик количества элементов

void Add(Binar_Tree **current, int data) //функция добавления элемента

30

{

if (*current!=NULL) //если дерево имеет значение

{

if (data<(*current)->data) //если введенное значение меньше

Add(&(*current)->left, data); //заполняем левую ветвь else if (data>(*current)->data) //если введенное значение больше

Add(&(*current)->right, data); //заполняем правую ветвь

}

else //если дерево не имеет значений

{

*current=new Binar_Tree; //создаем дерево (выделяем память)

(*current)->data=data; //корню присваиваем значение введенного

(*current)->left=NULL;

//создаем левую ветвь

(*current)->right=NULL; //создаем правую ветвь

countt++;

//счетчик увеличиваем на единицу

}}

void Changer(Binar_Tree **current, Binar_Tree **tmp) //функция замены

{

if ((*current)->right!=NULL) //если дерево имеет значение Changer(&(*current)->right, &(*tmp)); //рекурсивно вызываем функцию

замены else

{

(*tmp)->data=(*current)->data; //удаляемый узел заменяется крайним правым из левого дочернего узла

*tmp=*current;

*current = (*current)->left;

}

}

int Delete(Binar_Tree **current, int data) //функция удаления элемента дерева

{

int r=0; //переменная для передачи значений, что элемент удален if (*current!=NULL) //если дерево имеет значение

{

if (data<(*current)->data) //если удаляемый элемент меньше корня r=Delete(&(*current)->left, data); // обходим левую ветвь

else

if (data>(*current)->data) //если удаляемый элемент больше корня r=Delete(&(*current)->right, data); // обходим правую ветвь

else

{

Binar_Tree *tmp=*current; //создание временного указателя

31

if (tmp->right==NULL) //если правый лист дерева ноль *current=tmp->left; //удаляем введенный элемент

else

if (tmp->left==NULL) //если левый лист дерева ноль *current = tmp->right; //удаляем введенный элемент

else

Changer(&(*current)->left, &tmp); //переходим на замену delete tmp; //удаляем временный указатель

countt--; //счетчик уменьшаем на единицу

r=1;

//возвращаемому элементу присваиваем единицу

}}

 

 

return r; //возвращаем значение

}

 

 

void postorder(Binar_Tree *current) //функция обратного обхода дерева

{

 

 

if (current!=NULL)

//если дерево имеет значения

{

 

 

postorder(current->left);

//рекурсивно обходим левую ветвь

postorder(current->right);

//рекурсивно обходим правую ветвь

printf("%d ", current->data); //выводим на консоль

}}

void Show(Binar_Tree *current, int l) //функция отображения дерева

{

if (current!=NULL) //если дерево имеет значения

{

Show(current->right, l + 1); //рекурсивно обходим правую ветвь

for (int i=0; i<l; i++)

//цикл для построения в виде дерева

printf("\t");

//при помощи табуляции

printf("%d \n", current->data); //выводим на консоль

Show(current->left, l + 1); //рекурсивно обходим левую ветвь

}}

void Clear(Binar_Tree **current) //функция полной очистки дерева

{

if (*current!=NULL) //если дерево имеет значения

{

Clear(&(*current)->left); //рекурсивно очищаем левую ветвь Clear(&(*current)->right);//рекурсивно очищаем правую ветвь delete *current; //удаляем элементы

countt--; //уменьшаем счетчик

if (countt==0) //если счетчик равен нулю

*current = NULL; //то корень дерева равен нулю

}}

32

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]