Вы находитесь на странице: 1из 10

МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ

ЗАПОРІЗЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ


МАТЕМАТИЧНИЙ ФАКУЛЬТЕТ
КАФЕДРА ПРОГРАМНОЇ ІНЖЕНЕРІЇ

Дисципліна «Мова програмування Java»


Лабораторна робота № 6: “ Наслідування в Java"

Виконав студент гр. 6.1210-2пі


Новіков Олег

Перевірив: Викладач
Горбенко Віталій Іванович

Запоріжжя
2022
Завдання

1. Полное бинарное дерево и класс его реализации

Ниже представлена программа, в которой на основе конструкторов класса


создается полное бинарное дерево объектов — каждый объект имеет по две ссылки
на объекты того же класса. Каждый объект имеет три поля. Символьное (типа
char ) поле Level определяет уровень объекта: например, в вершине иерархии
находится объект уровня A, который ссылается на два объекта уровня B, которые,
в свою очередь, ссылаются на четыре объекта уровня C и т. д. Объекты
нумеруются, для чего используется целочисленное поле Number. Нумерация
выполняется в пределах одного уровня. Например, на верхнем уровне A всего один
объект с номером 1. На втором уровне B два объекта с номерами 1 и 2. На третьем
уровне C четыре объекта с номерами от 1 до 4 включительно и т.д. Описанная
структура объектов представлена на следующем рис.:

Кроме метки уровня и номера объекта на уровне, каждый объект еще имеет свій
«идентификационный код». Этот код генерируется случайным образом при
создании объекта и состоит по-умолчанию из восьми цифр (количество цифр в
коде определяется закрытым статическим целочисленным полем IDnum). Код
записывается в целочисленный массив, на который ссылается переменная массива
ID — закрытое поле класса ObjectTree.

Для вывода кода объекта используется закрытый метод showID(). Методом


последовательно выводятся на экран элементы массива ID, при этом в качестве
разделителя используется вертикальная черта. Сам метод вызывается в методе
show(), который предназначен для отображения параметров объекта: уровня
объекта в структуре, порядкового номера объекта на уровне и
идентификационного кода объекта. Открытые поля FirstRef и SecondRef являются
объектными переменными класса ObjectTree и предназначены для записи ссылок
на объекты следующего уровня. Присваивание значений этим переменным
выполняется при вызове конструктора класса.

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


полем value (для примера задайте ему тип int), а также:
- методом, который позволяет определить полноту дерева (т. е. наличие
левого и правого сына для всех объектов (узлов), кроме листьев и возможно
последнего узла-объекта, у которого может быть только левый сын);
- методом, который проверяет возможность добавления узла по указанному
адресу (уровень-номер);
- методом, который добавляет узел по указанному адресу;
- методом, который удаляет узел по указанному адресу;
- методом, который восстанавливает полноту двоичного дерева после
удаления узла;
- методом, который позволяет объединить два дерева.

При необходимости измените модификаторы доступа уже имеющихся методов и


полей.

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


построить структуру с указанным количеством объектов-узлов.

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


бинарного дерева. Переопределите метод восстановления полноты бинарного
дерева после удаления узла, на метод восстановления главного свойства Пирамиды
— у каждого из сыновей значение value больше, чем у отца. Переопределите
конструкторы так, чтобы они позволяли строить Пирамиду с поддержкой ее
главного свойства. Разработайте конструктор, который позволяет построить
Пирамиду на основе одномерного массива значений для его объектов.
Я вирішив трохи переробити клас Binary Tree. Виніс зберігання вузлів в окремий
клас Node:
package BinaryTree;

class Node {
int value;
Node left;
Node right;

Node(int value) {
this.value = value;
right = null;
left = null;
}
}

Далі, код для перевірки повноти дерева:


// вычисления общего количества узлов в бинарном дереве
private static int size(Node root)
{
if (root == null) {
return 0;
}
return 1 + size(root.left) + size(root.right);
}

// обход бинарного дерева и заполняем массив


public static void inorder(Node root, boolean[] A, int i)
{
if (root == null || i >= A.length) {
return;
}

// повторяем с индексом `2i+1` для левого узла


inorder(root.left, A, 2*i + 1);

// отметить индекс `i` как посещенный


A[i] = true;

// повториться с индексом `2i+2` для правого узла


inorder(root.right, A, 2*i + 2);
}

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


public static boolean isComplete(Node root, int n)
{
// возвращаем, если дерево пусто
if (root == null) {
return true;
}

// строим вспомогательный булев массив размера


boolean[] A = new boolean[n];

// заполняем массив
inorder(root, A, 0);

for (boolean e: A)
{
if (!e) {
return false;
}
}
return true;
}

Далі, методи додавання та видалення вузлів:


private Node addRecursive(Node current, int value) {
if (current == null) {
return new Node(value);
}

if (value < current.value) {


current.left = addRecursive(current.left, value);
} else if (value > current.value) {
current.right = addRecursive(current.right, value);
} else {
return current;
}

return current;
}
public void add(int value) {
root = addRecursive(root, value);
}

// Функция для выполнения неупорядоченного обхода


public static void inorder(Node root)
{
if (root == null) {
return;
}

inorder(root.left);
System.out.print(root.data + " ");
inorder(root.right);
}

// Вспомогательная функция для поиска узла максимального значения


public static Node findMaximumKey(Node ptr)
{
while (ptr.right != null) {
ptr = ptr.right;
}
return ptr;
}

// Рекурсивная функция для вставки ключа


public static Node insert(Node root, int key)
{
if (root == null) {
return new Node(key);
}

if (key < root.data) {


root.left = insert(root.left, key);
}
else {
root.right = insert(root.right, key);
}

return root;
}

// Функция для удаления узла


public static Node deleteNode(Node root, int key)
{
// ключ не найден в дереве
if (root == null) {
return null;
}

if (key < root.data) {


root.left = deleteNode(root.left, key);
}

else if (key > root.data) {


root.right = deleteNode(root.right, key);
}
else {
// удаляемый узел не имеет потомков
if (root.left == null && root.right == null){
return null;
}

// удаляемый узел имеет двух потомков


else if (root.left != null && root.right != null)
{
Node predecessor = findMaximumKey(root.left);

// копируем значение предшественника в текущий узел


root.data = predecessor.data;

// рекурсивно удаляем предшественника


root.left = deleteNode(root.left, predecessor.data);
}

// удаляемый узел имеет только одного потомка


else {
Node child = (root.left != null) ? root.left: root.right;
root = child;
}
}

return root;
}

public static void main(String[] args)


{
int[] keys = { 15, 10, 20, 8, 12, 25 };

Node root = null;


for (int key: keys) {
root = insert(root, key);
}

root = deleteNode(root, 12);


inorder(root);
}
Далі, об’єднання двох дерев:
public static void preorder(Node root)
{
if (root == null) {
return;
}

System.out.print(root.data + " ");


preorder(root.left);
preorder(root.right);
}

// Function to store inorder traversal


public static void inorder(Node root, List<Node> nodes)
{
if (root == null || nodes == null) {
return;
}

inorder(root.left, nodes);
nodes.add(root);
inorder(root.right, nodes);
}

// Function to merge two sorted lists into a single sorted list


public static List<Node> sortedMerge(List<Node> first, List<Node> second)
{
List<Node> result = new ArrayList<>();

int i = 0, j = 0;

while (i < first.size() && j < second.size())


{
if (first.get(i).data < second.get(j).data) {
result.add(first.get(i++));
}
else {
result.add(second.get(j++));
}
}

while (i < first.size()) {


result.add(first.get(i++));
}

while (j < second.size()) {


result.add(second.get(j++));
}

return result;
}

// Function to construct a balanced BST from a sorted list


public static Node toBalancedBST(List<Node> nodes, int low, int high)
{
if (low > high) {
return null;
}

int mid = (low + high) / 2;

Node root = nodes.get(mid);

root.left = toBalancedBST(nodes, low, mid - 1);

root.right = toBalancedBST(nodes, mid + 1, high);

return root;
}

// Function to merge two balanced BSTs into a single balanced BST


public static Node merge(Node a, Node b)
{

List<Node> first = new ArrayList<>();


inorder(a, first);

List<Node> second = new ArrayList<>();


inorder(b, second);

List<Node> sortedNodes = sortedMerge(first, second);

return toBalancedBST(sortedNodes, 0, sortedNodes.size() - 1);


}

Завдання 2. Конструктор:
BinaryTree(int levelCounter, int objectCounter, char level, int number) {
System.out.println("\tСоздан новый объект! " + level + "" + number);
objectCounter--;
this.level = level;
counter = number;
getID();
int tmp = objectCounter / 2;
//show();
if (levelCounter == 1 || objectCounter == 0) {
leftNode = null;
rightNode = null;
} else {
if (objectCounter >= 2) {
leftNode = new BinaryTree(levelCounter - 1, objectCounter - tmp, (char)
((int) level + 1), 2 * number - 1);
rightNode = new BinaryTree(levelCounter - 1, tmp, (char) ((int) level + 1),
2 * number);
} else if (objectCounter == 1) {
leftNode = new BinaryTree(levelCounter - 1, tmp, (char) ((int) level + 1),
2 * number - 1);
rightNode = null;
} else {
leftNode = null;
rightNode = null;
}
}
}

Завдання 3. Клас Pyramid:


import java.util.Arrays;

public class Pyramid extends BinaryTree {


Pyramid firstReference, secondReference;

Pyramid(int[] arr, char level, int counter) {


System.out.println("\tСоздан новый объект! " + level + "" + counter);
this.level = level;
this.counter = counter;

Arrays.sort(arr);

if (arr.length == 0) {
value = 0;
firstReference = null;
secondReference = null;
} else if (arr.length == 1) {
value = arr[0];
firstReference = null;
secondReference = null;
} else if (arr.length == 2) {
value = arr[0];
int[] arr1 = {arr[1]};
firstReference = new Pyramid(arr1, (char) ((int) level + 1), 2 *
counter - 1);
secondReference = null;
} else {
value = arr[0];
int tmp = arr.length - 1;
int[] arr1 = new int[tmp / 2];
int[] arr2 = new int[tmp - tmp / 2];

for (int i = 1, k1 = 0, k2 = 0; i < arr.length; i++) {


if (i % 2 == 0) {
arr1[k1] = arr[i];
k1++;
} else {
arr2[k2] = arr[i];
k2++;
}
}

firstReference = new Pyramid(arr2, (char) ((int) level + 1), 2 *


counter - 1);
secondReference = new Pyramid(arr1, (char) ((int) level + 1), 2 *
counter);
}
}

public boolean performCheck() {


if (firstReference != null && secondReference != null) {
if (value > firstReference.value) {
return false;
}
if (value > secondReference.value) {
return false;
}
return firstReference.performCheck() && secondReference.performCheck();
}
if (firstReference != null) {
if (value > firstReference.value) {
return false;
}
return firstReference.performCheck();
}
if (secondReference != null) {
if (value > secondReference.value) {
return false;
}
return secondReference.performCheck();
}
return true;
}

public void out() {


out(level);
}

public void out(char L) {


int i = (int) level - (int) L;
for (int j = 0; j < i; j++) {
System.out.print("\t");
}
System.out.println(level + "" + counter + ": " + value);
if (firstReference != null) firstReference.out(L);
if (secondReference != null) secondReference.out(L);
}

public void repair() {


repair(this);
}

private void repair(Pyramid head) {


if (firstReference != null) {
if (value > firstReference.value) {
int tmp = value;
value = firstReference.value;
firstReference.value = tmp;
head.repair();
return;
}
firstReference.repair();
}
if (secondReference != null) {
if (value > secondReference.value) {
int tmp = value;
value = secondReference.value;
secondReference.value = tmp;
head.repair();
return;
}
secondReference.repair();
}
}
}

Вам также может понравиться