9. Деревья 9.1. Реализовать абстрактный класс Tree – базовый

advertisement
9. Деревья
9.1. Реализовать абстрактный класс Tree – базовый класс, описывающий общий интерфейс
для двоичных деревьев поиска.
Объявите структуру Node (узел дерева) в разделе public класса Tree. Узел должен
содержать поле данных типа int, указатели на левое и правое поддеревья, указатель на
родителя и высоту (типа int) поддерева с корнем в данном узле. Для класса Tree
объявите следующие чистые виртуальные функции:
a) void insert(int x) – метод добавления нового элемента в дерево;
b) void remove(Node *p) – метод, удаляющий из дерева узел по указателю p;
Реализуйте следующие методы:
c) int get_height(Node *p) – метод, возвращающий высоту поддерева с
корнем в узле p. Если p == NULL, то возвращается -1.
d) node* find(int x) – метод поиска элемента по значению х. Если элемент
найден, то возвращается указатель на узел, содержащий данный элемент, в
противном случае возвращается NULL.
e) методы нахождения наибольшего и наименьшего элементов:
 Node* minimum(Node *p) – метод, возвращающий указатель на
наименьший элемент поддерева с корнем в узле p;
 Node* maximum(Node *p) – метод, возвращающий указатель на
наибольший элемент поддерева с корнем в узле p;
f) методы нахождения предшествующего и последующего элементов:
 Node* predecessor(const Node *p) – метод, возвращающий
указатель на узел, предшествующий по ЗНАЧЕНИЮ узлу p. Если такого
узла не найдено (то есть p хранит наименьший элемент), вернуть NULL;
 Node* successor(const Node *p) – метод, возвращающий
указатель на узел, следующий по ЗНАЧЕНИЮ за узлом p. Если такого узла
не найдено (то есть p хранит наибольший элемент), вернуть NULL;
g) три варианта обхода дерева в глубину (методы должны выводить на экран
элементы дерева в порядке, соответствующем обходу):
 void in_order_traversal();
 void pre_order_traversal();
 void post_order_traversal();
h) void breadth_first_traversal() – обход дерева в ширину (при
реализации можно использовать контейнер queue из STL);
i) (необязательный пункт) перегрузить оператор вывода в предположении, что в
дереве хранятся только однозначные или двузначные натуральные числа.
Отображать дерево следует в любой удобной Вам форме, этот оператор
понадобится Вам при реализации сбалансированного дерева. Например, вывод
дерева на экран может выглядеть следующим образом:
От класса Tree унаследуйте класс BSTree (binary search tree) – двоичное дерево поиска.
В данном классе реализуйте виртуальные методы insert и remove. При этом при
выполнении этих методов высоты всех поддеревьев должны автоматически пересчитываться, но вычислительная сложность методов должна оставаться равной O(h), где
h – это высота всего дерева.
Описания интерфейсов классов должны содержаться в отдельных h-файлах (tree.h,
bs_tree.h), а вся реализация – в cpp-файлах (tree.cpp, bs_tree.cpp). Не забудьте про
конструкторы и деструкторы. Не забудьте про правило трех: запретите использование
конструкторов копирования и операторов присваивания или перегрузите их.
В функции main создайте динамический объект класса BSTree через указатель
Tree* p = new BSTree, заполните дерево случайными натуральными числами, не
превышающими 100. Вызовите все методы обхода дерева. Используя метод
successor, выведите на экран только четные элементы дерева в порядке возрастания,
с помощью метода predecessor выведите на экран только нечетные элементы в
порядке убывания. Удалите из дерева все элементы, кратные трем. Выведите дерево с
помощью любого метода обхода. Удалите динамический объект.
9.2. Добавьте в проект ещё два файла и реализуйте класс AVLTree (АВЛ-дерево), хранящее
целые числа типа int. Для этого достаточно унаследовать класс AVLTree от класса
Tree и переопределить только два метода insert и remove. Для удобства повороты
и балансировку дерева выделите в отдельные методы:
 int balance_factor(const Node *p) – метод, вычисляющий
коэффициент сбалансированности (balance factor) узла p;
 void reset_height(Node *p) – метод, пересчитывающий высоту поддерева с узлом в корне p;
 void rotate_right(Node *p) – метод, осуществляющий правый поворот
вокруг узла p;
 void rotate_left(Node *p) – метод, осуществляющий левый поворот
вокруг узла p;
 void balance(Node *p) – метод, осуществляющий балансировку
поддерева с корнем в узле p;
 не забудьте про деструктор и правило трех.
В некотором файле tree.in описаны действия, совершаемые над двоичным деревом
поиска, в файле tree.out выведите результат выполнения описанных действий.
Формат входного файла
В первой строке файла tree.in записано целое число (0 или 1), 0 означает, что будет
рассматриваться обычное двоичное дерево поиска, 1 – АВЛ-дерево. Далее в каждой
строке описывается действие и соответствующие параметры:
 i x – добавить элемент x (0 < x < 100) в дерево;
 d x – удалить элемент x (0 < x < 100) из дерева;
 ino – вывести в выходной файл все элементы дерева в соответствии с in-order
обходом;
 preo – вывести в выходной файл все элементы дерева в соответствии с pre-order
обходом;
 posto – вывести в выходной файл все элементы дерева в соответствии с post-order
обходом;
 bfs – вывести в выходной файл все элементы дерева в соответствии с обходом в
ширину;
 h – вывести в выходной файл высоту дерева.
Формат выходного файла
В файле tree.out должен содержаться результат выполнения команд, описанных в файле
tree.in: каждый результат должен быть выведен в отдельной строке.
Примеры
tree.in
0
i 20
i 4
i 15
preo
h
1
i 20
i 4
i 15
preo
h
1
i 1
i 2
i 3
d 2
d 1
d 3
h
i 4
h
1
i 5
i 2
i 8
i 1
i 3
i 7
i 10
i 4
i 6
i 9
i 11
i 12
bfs
h
d 1
bfs
h
tree.out
20 4 15
2
15 4 20
1
-1
0
5 2 8 1 3 7 10 4 6 9 11 12
4
8 5 10 3 7 9 11 2 4 6 12
3
Хеш-таблицы
9.3. В файле tale.in записан текст на некотором языке, использующем латинский алфавит.
Известно, что длина каждого слова не превосходит восьми символов. Слова разделены
пробелами, точками, запятыми и переносами строки. Вам необходимо сосчитать частоту
вхождения каждого слова в данный текст. Для этого следует использовать хеш-таблицу,
ключом для которой будет служить строка символов. Максимальная длина строки –
восемь символов, если строка короче, то остальные символы считаются равными ‘\0’.
Пусть строка хранится в массиве char str[8], тогда значение хеш-функции будет
вычисляться по формуле:
,
где m – размер таблицы, любое простое число больше 127, а значения принадлежат
множеству {0, 1, 2, … m-1}. Выберите самостоятельно некоторое значение m, числа
можно также придумать самостоятельно или определять их случайным образом до
начала построения таблицы.
Для хеш-таблицы должен быть определен метод add(char *str), который будет
добавлять строку str в таблицу и устанавливать её счетчик «встречаемости» равным
единицы, если же данная строка уже находится в таблице, то её счетчик должен
увеличиться на единицу. После обработки всего текста выведите на экран в любом
порядке слова и соответствующие им частоты.
Примечание
Используйте метод цепочек (списков) для разрешения коллизий в хеш-таблице.
Пример
tale.in
вывод на экран
quod licet iovi, non licet bovi quod - 1
licet - 2
iovi - 1
non - 1
bovi - 1
Ассоциативные контейнеры set и map стандартной библиотеки
9.4. Напишите шаблонную функцию пересечения двух множеств, типы элементов которых
совпадают. Напишите шаблонную функцию объединения двух множеств, типы
элементов которых совпадают. Напишите шаблонную функцию, принимающую
множество множеств и возвращающую значение «истина», если оно является
замкнутым относительно объединения и пересечения. Реализуйте класс point,
описывающий точку на плоскости. Перегрузите для данного класса операторы
ввода/вывода и оператор сравнения < (будем считать, что (x1, y1) < (x2, y2), если либо
x1 < x2, либо x1 = x2 и y1 < y2). Пользователь вводит с экрана пять точек (то есть пять пар
чисел (xi, yi)). Пусть данные точки образуют множество A. Найдите множество B всех
подмножеств множества А, выведите множество В на экран. Определите, будет ли
множество В замкнутым относительно объединения и пересечения.
9.5. В файле dict.txt содержится описание шифра: в каждой строке файла записано целое
число n (1 ≤ n ≤ 32000), пробел и слово, соответствующее этому числу. Считайте данный
файл и постройте на его основе отображение map. Пользователь вводит зашифрованный текст (целые числа, разделенные пробелами, признак конца ввода – число
ноль). Расшифруйте послание пользователя, используя построенное отображение. Если
какое-то число отсутствует в шифре, то при расшифровке его надо проигнорировать.
Файл dict.txt
569 a
570 the
17 know
321 treasure
3 secret
123 I
Пример входных данных
123 17 569 47 3 0
Пример выходных данных
I know a secret
Download