Бинарное дерево поиска. Класс BinaryTree. Целые числа. Числа могут повторяться
В данной работе приведен пример разработки класса, реализующего дерево бинарного поиска для целых чисел (int). По подобному образцу можно разрабатывать другие классы, реализующие дерево бинарного поиска.
Содержание
- 1. Условие задачи
- 2. Решение. Текст программы
- 2.1. Объявление класса BinaryTree
- 2.2. Структура Node
- 2.3. Ввод внутренних полей класса
- 2.4. Конструктор BinaryTree()
- 2.5. Метод Put(Node*, int)
- 2.6. Метод ShowSorted(Node*)
- 2.7. Метод Free(Node*)
- 2.8. Деструктор
- 2.9. Метод Get(int)
- 2.10. Метод ToSortedArray()
- 2.11. Метод Copy(Node**, Node*)
- 2.12. Конструктор копирования BinaryTree(const BinaryTree&)
- 2.13. Оператор копирования operator=(const BinaryTree& obj)
- 2.14. Метод Show().Вывести элементы дерева в произвольном порядке
- 2.15. Метод Size(). Размер дерева
- 3. Тест. Функция main()
- 4. Сокращенный код программы
- Связанные темы
Поиск на других ресурсах:
1. Условие задачи
Разработать класс дерева бинарного поиска, содержащий следующие методы (API класса):
- BinaryTree() – конструктор – создает пустое дерево;
- void ShowSorted(string msg) – отображает элементы дерева в отсортированном виде;
- void Put(int value) – добавляет элемент в дерево;
- ~BinaryTree() – деструктор (освобождает память);
- int Get(int value) – возвращает кол-во вхождений элемента в дерево. Если элемент отсутствует, возвращается 0;
- int Size() – возвращает количество элементов в дереве;
- int* ToSortedArray() – конвертирует дерево в отсортированный массив;
- void Show(string msg) – вывести дерево в произвольном порядке;
- BinaryTree(const BinaryTree& obj) – конструктор копирования
- BinaryTree& operator=(const BinaryTree& obj) – оператор копирования.
⇑
2. Решение. Текст программы
Для решения задачи выбран способ рекурсивного вызова базовых методов класса.
2.1. Объявление класса BinaryTree
В начале объявляется пустой класс BinaryTree
#include <iostream> using namespace std; // Дерево бинарного поиска class BinaryTree { };
2.2. Структура Node
Узел дерева описывается структурой, изображенной на рисунке 1.
Рисунок 1. Схематическое изображение узла дерева бинарного поиска
Программный код узла Node следующий
class BinaryTree { private: struct Node { int value; int count; Node* left; Node* right; }; };
2.3. Ввод внутренних полей класса
Дерево бинарного поиска начинается с корня. В программе этому корню соответствует переменная с именем root.
Также приложение содержит метод конвертирования дерева в отсортированный массив. Поэтому для сохранения массива вводятся две дополнительные переменные: массив и их размер.
Дерево бинарного поиска начинается с корня. В программе этому корню соответствует переменная с именем root.
Также приложение содержит метод конвертирования дерева в отсортированный массив. Поэтому для сохранения массива вводятся две дополнительные переменные: массив и их размер.
class BinaryTree { private: ... Node* root; // корень дерева int* A; // дерево в виде отсортированного массива int size; // размер массива ... };
2.4. Конструктор BinaryTree()
В конструкторе создается дерево, не содержащее никаких элементов.
class BinaryTree { ... public: // Конструктор - создает пустое дерево BinaryTree() { root = nullptr; A = nullptr; size = 0; } };
2.5. Метод Put(Node*, int)
В методе Put() реализуется добавление нового элемента в дерево. Метод имеет две перегруженные реализации
private: Node* Put(Node* x, int value); public: void Put(int value);
Первая реализация в разделе private – это непосредственное добавление элемента посредством рекурсивного вызова функции Put(). Вторая реализация в разделе public доступна для клиентского кода и обращается к первой реализации.
// Дерево бинарного поиска class BinaryTree { private: ... Node* Put(Node* x, int value) { if (x == nullptr) { // Создать узел и вернуть его Node* p = new Node; p->value = value; p->count = 1; p->left = nullptr; p->right = nullptr; return p; } if (value == x->value) { x->count++; return x; } if (value < x->value) { x->left = Put(x->left, value); return x; } if (value > x->value) { x->right = Put(x->right, value); return x; } } public: // Добавляет элемент в дерево void Put(int value) { // Вызвать рекурсивную функцию if (root == nullptr) root = Put(root, value); else Put(root, value); } };
2.6. Метод ShowSorted(Node*)
Метод ShowSorted() имеет скрытую (private) и общедоступную (public) реализацию
private: void ShowSorted(Node* x); public: void ShowSorted(string msg)
Текст реализаций метода следующий:
// Дерево бинарного поиска class BinaryTree { private: ... // Отображение дерева в отсортированном виде void ShowSorted(Node* x) { if (x == nullptr) return; if (x->left != nullptr) ShowSorted(x->left); cout << x->value << ":" << x->count << " "; if (x->right != nullptr) ShowSorted(x->right); } public: ... void ShowSorted(string msg) { cout << msg << " => "; ShowSorted(root); cout << endl; } };
2.7. Метод Free(Node*)
Рекурсивный метод Free() вызывается из деструктора и оператора присваивания копированию.
// Дерево бинарного поиска class BinaryTree { private: ... // Метод, освобождающий память, выделенную под массив void Free(Node* x) { if (x == nullptr) return; if (x->left != nullptr) Free(x->left); if (x->right != nullptr) Free(x->right); delete x; } };
2.8. Деструктор
// Дерево бинарного поиска class BinaryTree { ... public: // Деструктор ~BinaryTree() { // Освободить память, выделенную под дерево Free(root); // Освободить массив A, если он существует if (size > 0) delete[] A; } };
2.9. Метод Get(int)
Метод Get() предназначен для определения количества вхождений элемента в дереве. Если метод возвращает 0, это означает, что элемента в дереве нет. Как и все остальные подобные методы класса, метод перегружен двумя реализациями: общедоступной (public) и скрытой (private). Скрытая реализация определяет элемент путём рекурсивного вызова метода.
// Дерево бинарного поиска class BinaryTree { private: ... Node* Get(Node* x, int value) { if (x == nullptr) return nullptr; if (value < x->value) return Get(x->left, value); else if (value > x->value) return Get(x->right, value); else return x; } public: ... // Возвращает кол-во вхождений элемента в дереве int Get(int value) { Node* p = Get(root, value); if (p == nullptr) return 0; return p->count; } };
2.10. Метод ToSortedArray()
Метод ToSortedArray() предназначен для конвертирования дерева в отсортированный массив. Массив создается в динамической памяти с помощью оператора new. Внутреннее поле класса с именем A является указателем на массив. Размер массива определяет поле size.
Метод ToSortedArray() имеет две перегруженные реализации в разделах private и public.
// Дерево бинарного поиска class BinaryTree { private: ... // Преобразование из бинарного дерева в отсортированный массив void ToSortedArray(Node* x, int* current) { if (x == nullptr) return; if (x->left != nullptr) ToSortedArray(x->left, current); // Врахувати count for (int i = 0; i < x->count; i++) { A[*current] = x->value; (*current)++; } if (x->right != nullptr) ToSortedArray(x->right, current); } public: // Конвертирует дерево в отсортированный массив const int* ToSortedArray() { // 1. Получить размер массива и выделить память size = Size(); A = new int[size]; size = 0; ToSortedArray(root, &size); return A; } };
2.11. Метод Copy(Node**, Node*)
Одной из операций над деревом является получение копии этого дерева. С этой целью в класс вводится специальный метод Copy(). Этот метод является внутренним и вызывается из конструктора копирования и оператора присвоения копированием.
// Дерево бинарного поиска class BinaryTree { private: ... // Функция копирования *x_copy <= x void Copy(Node** x_copy, Node* x) { if (x == nullptr) return; // Сделать копию ячейки *x_copy = new Node; (*x_copy)->value = x->value; (*x_copy)->count = x->count; (*x_copy)->left = nullptr; (*x_copy)->right = nullptr; // Перейти на наступні рівні Copy(&(*x_copy)->left, x->left); Copy(&(*x_copy)->right, x->right); } ... };
2.12. Конструктор копирования BinaryTree(const BinaryTree&)
Конструктор копирования является технической составляющей класса и необходим в случаях, когда нужно получить копию объекта, когда он инициализируется значением другого объекта.
// Дерево бинарного поиска class BinaryTree { private: ... public: ... // Конструктор копирования BinaryTree(const BinaryTree& obj) { Copy(&root, obj.root); } ... };
2.13. Оператор копирования operator=(const BinaryTree& obj)
Оператор копирования выполняет ту же функцию, что и конструктор копирования. Только в этом случае принимающий объект уже существует и он переопределяется другим объектом.
// Дерево бинарного поиска class BinaryTree { ... public: ... // Оператор копирования BinaryTree& operator=(const BinaryTree& obj) { if (this != &obj) // нет ли присваивания самому себе { // Освободить предварительно выделенную память Free(root); // Скопировать данные Copy(&root, obj.root); } return *this; } };
2.14. Метод Show().Вывести элементы дерева в произвольном порядке
Особым случаем вывода дерева является его вывод в том порядке, как в нем сформированы элементы в направлении сверху вниз. Это произвольный порядок, который определен входной последовательностью, формирующей дерево.
Метод имеет две реализации. Первая – скрытая реализация, реализующая непосредственно вывод. Вторая реализация общедоступна и может быть вызвана из клиентского кода.
// Дерево бинарного поиска class BinaryTree { private: ... // Функция, выводящая дерево в произвольном порядке void Show(Node* x) { if (x == nullptr) return; // Вывести элемент cout << x->value << ":" << x->count << " "; // Перейти на следующие узлы Show(x->left); Show(x->right); } public: ... // Вывести дерево в произвольном порядке void Show(string msg) { cout << msg << " => "; Show(root); } };
2.15. Метод Size(). Размер дерева
Метод Size() возвращает количество элементов в дереве. Как и все предыдущие методы, этот метод имеет скрытую и общедоступную реализацию.
// Дерево бинарного поиска class BinaryTree { private: ... int Size(Node* x) { if (x == nullptr) return 0; int count = 0; if (x->left != nullptr) count = count + Size(x->left); if (x->right != nullptr) count = count + Size(x->right); return count + x->count; } public: ... // Возвращает количество элементов в дереве int Size() { return Size(root); } }; // Дерево бинарного поиска class BinaryTree { private: ... int Size(Node* x) { if (x == nullptr) return 0; int count = 0; if (x->left != nullptr) count = count + Size(x->left); if (x->right != nullptr) count = count + Size(x->right); return count + x->count; }
3. Тест. Функция main()
В функции main() можно проводить тест работы дерева.
void main() { // Создать дерево без элементов BinaryTree BT; // Добавить к дереву элементы BT.Put(10); BT.Put(8); BT.Put(8); BT.Put(17); BT.Put(11); BT.Put(11); BT.Put(11); BT.Put(23); BT.Put(5); BT.Put(12); // Вывести дерево в отсортированном виде BT.ShowSorted("BT"); // Тест конструктора копирования BinaryTree BT2 = BT; BT2.ShowSorted("BT2"); // Тест оператора копирования BinaryTree BT3; BT3 = BT2; BT3.Show("BT3"); // Конвертировать дерево в массив const int* A = BT3.ToSortedArray(); // Вывести отсортированный массив cout << endl; for (int i = 0; i < BT3.Size(); i++) cout << A[i] << " "; cout << endl; }
4. Сокращенный код программы
Ниже представлен сокращенный код всех функций класса с их объявлениями без реализации.
#include <iostream> using namespace std; // Дерево бинарного поиска class BinaryTree { private: struct Node { ... }; Node* root; // корень дерева int* A; // дерево в виде отсортированного массива int size; // размер массива Node* Put(Node* x, int value) { ... } // Отображение дерева в отсортированном виде void ShowSorted(Node* x) { ... } // Метод, освобождающий память, выделенную под массив void Free(Node* x) { ... } Node* Get(Node* x, int value) { ... } int Size(Node* x) { ... } // Преобразование из бинарного дерева в отсортированный массив void ToSortedArray(Node* x, int* current) { ... } // Функция копирования *x_copy <= x void Copy(Node** x_copy, Node* x) { ... } // Функція, выводящая дерево в произвольном порядке void Show(Node* x) { ... } public: // Конструктор - создает пустое дерево BinaryTree() { ... } void ShowSorted(string msg) { ... } // Добавляет элемент в дерево void Put(int value) { ... } // Деструктор ~BinaryTree() { ... } // Возвращает кол-во вхождений элемента в дереве int Get(int value) { ... } // Конвертирует дерево в отсортированный массив const int* ToSortedArray() { ... } // Возвращает количество элементов в дереве int Size() { ... } // Вывести дерево в произвольном порядке void Show(string msg) { ... } // Конструктор копирования BinaryTree(const BinaryTree& obj) { ... } // Оператор копирования BinaryTree& operator=(const BinaryTree& obj) { ... } }; void main() { ... }
Связанные темы