From 9c037c5aeda554dbbbe58b249e6c3e93866c5a33 Mon Sep 17 00:00:00 2001 From: Samuel Oberhofer Date: Mon, 6 Jun 2022 13:36:46 +0200 Subject: [PATCH] Avl Stuff --- Uebung 2/2.3/Makefile | 51 +++++++++++ Uebung 2/2.3/avlNode.cpp | 181 +++++++++++++++++++++++++++++++++++++++ Uebung 2/2.3/avlNode.h | 25 ++++++ Uebung 2/2.3/main.cpp | 43 ++++++++++ 4 files changed, 300 insertions(+) create mode 100644 Uebung 2/2.3/Makefile create mode 100644 Uebung 2/2.3/avlNode.cpp create mode 100644 Uebung 2/2.3/avlNode.h create mode 100644 Uebung 2/2.3/main.cpp diff --git a/Uebung 2/2.3/Makefile b/Uebung 2/2.3/Makefile new file mode 100644 index 0000000..7c25eb6 --- /dev/null +++ b/Uebung 2/2.3/Makefile @@ -0,0 +1,51 @@ + +# Name of the binary for Development +BINARY = main +# Name of the binary for Release +FINAL = prototyp +# Object files +OBJS = main.o avlNode.o +# Compiler flags +CFLAGS = -g #-std=c++17 #-fsanitize=address,undefined -Werror -Wall +# Linker flags +LFLAGS = #-fsanitize=address,undefined +#Which Compiler to use +COMPILER = c++ + + +# all target: builds all important targets +all: binary + +final : ${OBJS} + ${COMPILER} ${LFLAGS} -o ${FINAL} ${OBJS} + +binary : ${OBJS} + ${COMPILER} ${LFLAGS} -o ${BINARY} ${OBJS} + +# Links the binary +${BINARY} : ${OBJS} + ${COMPILER} ${LFLAGS} -o ${BINARY} ${OBJS} + + +# Compiles a source-file (any file with file extension .c) into an object-file +# +# "%" is a wildcard which matches every file-name (similar to * in regular expressions) +# Such a rule is called a pattern rule (because it matches a pattern, see https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html), +# which are a form of so called implicit rules (see https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html) +# "$@" and "$<" are so called automatic variables (see https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html) +%.o : %.cpp + ${COMPILER} -c ${CFLAGS} -o $@ $< + + +# Rules can not only be used for compiling a program but also for executing a program +run: ${BINARY} + ./${BINARY} + + +# Delete all build artifacts +clean : + rm -rf ${BINARY} ${OBJS} + + +# all and clean are a "phony" targets, meaning they are no files +.PHONY : all clean diff --git a/Uebung 2/2.3/avlNode.cpp b/Uebung 2/2.3/avlNode.cpp new file mode 100644 index 0000000..42c2a68 --- /dev/null +++ b/Uebung 2/2.3/avlNode.cpp @@ -0,0 +1,181 @@ +#include "avlNode.h" + +AvlNode::AvlNode(int key) { + this->left = nullptr; + this->right = nullptr; + this->key = key; + this->height = 1; +} + +// helper function which returns the max of the two inputs +int AvlNode::max(int n1, int n2) { return (n1 > n2) ? n1 : n2; } + +// caluclate height difference of a given Node by calculating difference of +// heights of left and right subtree +int AvlNode::getHeightDifference() { + int diff; + if (this == nullptr) { + diff = 0; + } else { + diff = this->left->getHeight() - this->right->getHeight(); + } + return diff; +} + +// returns height of a given AVL Node +int AvlNode::getHeight() { + if (this == nullptr) { + return 0; + } else { + return this->height; + } +} + +// insert a new node by recursively going to the sorted position which yields +// nullptr +AvlNode *AvlNode::insert(int key) { + if (this == nullptr) { + AvlNode *newNode = new AvlNode(key); + return newNode; + } else if (key > this->key) { + this->right = this->right->insert(key); + } else if (key < this->key) { + this->left = this->left->insert(key); + } else { + return this; + } + // update heights of all other nodes + this->height = + 1 + this->max(this->left->getHeight(), this->right->getHeight()); + + int diff = this->getHeightDifference(); + // check if rebalancing is necessary + if (diff > 1) { // check which kind of rebalancing is necessary + if (key > this->left->key) { + this->left = this->left->leftRotation(); + return this->rightRotation(); + + } else if (key < this->left->key) { + return this->rightRotation(); + } + } else if (diff < -1) { // check which kind of rebalancing is necessary + if (key > this->right->key) { + return this->leftRotation(); + } else if (key < this->right->key) { + this->right = this->right->rightRotation(); + return this->leftRotation(); + } + } + return this; +} + +// perform a left rotation (see lecture) +AvlNode *AvlNode::leftRotation() { + std::cout << "Do a left rotation on node " << this->key << "\n"; + AvlNode *rightNode = this->right; + AvlNode *leftOfRightNode = rightNode->left; + + rightNode->left = this; + this->right = leftOfRightNode; + + // update heights + this->height = + this->max(this->left->getHeight(), this->right->getHeight()) + 1; + rightNode->height = + this->max((rightNode->left->getHeight()), rightNode->right->getHeight()) + + 1; + return rightNode; +} + +// perform a right rotation (see lecture) +AvlNode *AvlNode::rightRotation() { + std::cout << "Do a right rotation on node " << this->key << "\n"; + AvlNode *leftNode = this->left; + AvlNode *rightOfLeftNode = leftNode->right; + + leftNode->right = this; + this->left = rightOfLeftNode; + + // update heights + this->height = + this->max(this->left->getHeight(), this->right->getHeight()) + 1; + leftNode->height = + this->max(leftNode->left->getHeight(), leftNode->right->getHeight()) + 1; + return leftNode; +} + +// function to print an AVL tree in pre-order: (sub)root, left (sub)tree, right +// (sub)tree +std::string AvlNode::printPreorder() { + std::stringstream output; + output << "node:\t" << this->key << ",\t"; + output << "height:\t" << this->getHeight() << ",\t"; + output << "Diff:\t" << this->getHeightDifference() << "\n"; + + if (this->left != nullptr) { + output << this->left->printPreorder(); + } + if (this->right != nullptr) { + output << this->right->printPreorder(); + } + return output.str(); +} + +AvlNode *AvlNode::deleteItem(int key) { + AvlNode *node = this; + + if (node == nullptr) { + return this; + } else if (key < node->key) { + node->left = node->left->deleteItem(key); + } else if (key > node->key) { + node->right = node->right->deleteItem(key); + } else { + // AvlNode *deleteNode = node; + if (node->left == nullptr && node->right == nullptr) { + delete node; + node = nullptr; + return nullptr; + } else if (node->left == nullptr) { // only children in right subtree + AvlNode *temp = node; + node = node->right; + delete temp; + } else if (this->right == nullptr) { // only children in left subtree + AvlNode *temp = node; + node = node->left; + delete temp; + } else { // we have to keep the BST structure, here, we look for the minimum + // in the right subtree (see lecture) + AvlNode *temp = node->right; + while (temp->left != nullptr) { + temp = temp->left; + } + node->key = temp->key; + node->right = node->right->deleteItem(temp->key); + } + } + this->height = 1 + max(this->left->getHeight(), this->right->getHeight()); + int diff = this->getHeightDifference(); + + if (diff > 1) { + if (this->left->getHeightDifference() >= 0) { + // Left Left Case + return this->rightRotation(); + } else { + // Left Right Case + this->left = this->left->leftRotation(); + return this->rightRotation(); + } + } + if (diff < -1) { + if (this->right->getHeightDifference() <= 0) { + // Right Right Case + return this->leftRotation(); + } else { + // Right Left Case + this->right = this->right->rightRotation(); + return this->leftRotation(); + } + } + return node; +} \ No newline at end of file diff --git a/Uebung 2/2.3/avlNode.h b/Uebung 2/2.3/avlNode.h new file mode 100644 index 0000000..05569fe --- /dev/null +++ b/Uebung 2/2.3/avlNode.h @@ -0,0 +1,25 @@ +#include +#include +#include + +#pragma once + +class AvlNode { +public: + int key; + AvlNode *left; + AvlNode *right; + int height; + + AvlNode(int key); + + int max(int n1, int n2); + int getHeightDifference(); + int getHeight(); + + AvlNode *insert(int key); + AvlNode *leftRotation(); + AvlNode *rightRotation(); + AvlNode *deleteItem(int key); + std::string printPreorder(); +}; diff --git a/Uebung 2/2.3/main.cpp b/Uebung 2/2.3/main.cpp new file mode 100644 index 0000000..a8cb787 --- /dev/null +++ b/Uebung 2/2.3/main.cpp @@ -0,0 +1,43 @@ +#include "avlNode.h" +#include +#include + +int main() { + AvlNode *root = new AvlNode(10); + // always give the root, as it could be changed with any insertion (in + // comparison to BST!) + root = root->insert(15); + root = root->insert(5); + root = root->insert(8); + root = root->insert(3); + root = root->insert(9); + root = root->insert(16); + root = root->insert(17); + root = root->deleteItem(10); + + for (int i = 20; i <= 50; i++) { + root = root->insert(i); + } + + // root = root->deleteItem(5); + + /* -- Scenarion 1 - rightRotation -- */ + // root = root->insert(2); + + /* -- Scenarion 2 - leftRotation -- */ + // root = root->insert(17); + // root = root->insert(19); + + /* -- Scenarion 3 - rightRotation, then leftRotation -- */ + // root = root->insert(17); + // root = root->insert(16); + + /* -- Scenarion 4 - leftRotation, then rightRotattion -- */ + // root = root->insert(17); + // root = root->insert(6); + // root = root->insert(7); + + std::cout << root->printPreorder(); + std::cout << "Perfectly balanced! As all things should be!\n"; + return 0; +} \ No newline at end of file