333 lines
9.9 KiB
C++
Executable File
333 lines
9.9 KiB
C++
Executable File
/*************************************************
|
|
* ADS Praktikum 1.2
|
|
* Tree.cpp
|
|
* Erweiterung um Hilfsfunktionen gestattet.
|
|
*************************************************/
|
|
#include "Tree.h"
|
|
#include "TreeNode.h"
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <queue>
|
|
|
|
using namespace std;
|
|
|
|
|
|
Tree::Tree() {
|
|
currentNodeChronologcalID = 0;
|
|
}
|
|
Tree::~Tree() {
|
|
while (m_anker != nullptr) {
|
|
deleteNode(m_anker->getNodeOrderID());
|
|
}
|
|
}
|
|
|
|
TreeNode* Tree::getAnker() {
|
|
return m_anker;
|
|
}
|
|
|
|
void Tree::setAnker(TreeNode* node) {
|
|
m_anker = node;
|
|
}
|
|
|
|
void Tree::addNode(string Name, int Age, double Income, int PostCode) {
|
|
TreeNode* newNode = new TreeNode { Age + int(Income) + PostCode , currentNodeChronologcalID++, Name, Age, Income, PostCode };
|
|
TreeNode* ptr = getAnker();
|
|
TreeNode* tmp = nullptr;
|
|
|
|
/*
|
|
* Allg. Baumaufbau
|
|
* Anker
|
|
* klein -> groß
|
|
*/
|
|
|
|
// bis zum passenden Parentknoten traversieren
|
|
while (ptr != nullptr) {
|
|
tmp = ptr;
|
|
// wenn NodeID > ptrID dann rechts sonst links
|
|
// Dublikate?
|
|
newNode->getNodeOrderID() > ptr->getNodeOrderID() ?
|
|
ptr = ptr->getRight() : ptr = ptr->getLeft();
|
|
}
|
|
|
|
if (getAnker() == nullptr)
|
|
setAnker(newNode);
|
|
|
|
// wenn NodeID > tmpID dann rechts sonst links
|
|
else newNode->getNodeOrderID() > tmp->getNodeOrderID() ?
|
|
tmp->setRight(newNode) : tmp->setLeft(newNode);
|
|
}
|
|
|
|
bool Tree::deleteNode(int delNodeID) {
|
|
// Baum ist leer
|
|
if (!getAnker())
|
|
return false;
|
|
|
|
// Loeschen von Nodes - ab Wurzel
|
|
if (getAnker()->getNodeOrderID() == delNodeID) {
|
|
|
|
// 1. Fall: der Baum bestehet aus 1 Knoten.
|
|
if (!getAnker()->getRight() && !getAnker()->getLeft()) {
|
|
delete getAnker();
|
|
setAnker(nullptr);
|
|
cout << "+ Datensatz wurde gelöscht.\n";
|
|
return true;
|
|
}
|
|
|
|
// 2. Fall: Wurzel, mit einem Nachfolger
|
|
else if ((getAnker()->getRight() && !getAnker()->getLeft()) || (!getAnker()->getRight() && getAnker()->getLeft())) {
|
|
TreeNode* tmp = getAnker();
|
|
|
|
// Nachfolger wird Anker
|
|
getAnker()->getRight() ?
|
|
setAnker(getAnker()->getRight()) : setAnker(getAnker()->getLeft());
|
|
delete tmp;
|
|
cout << "+ Datensatz wurde gelöscht.\n";
|
|
return true;
|
|
}
|
|
|
|
// 3. Fall: Wurzel, mit zwei Nachfolger
|
|
else if (getAnker()->getRight() && getAnker()->getLeft()) {
|
|
TreeNode* minimumRTB = getAnker()->getRight();
|
|
TreeNode* minimumParent = nullptr;
|
|
|
|
// Minimum von RTB suchen.
|
|
while (minimumRTB->getLeft() != nullptr) {
|
|
minimumParent = minimumRTB;
|
|
minimumRTB = minimumRTB->getLeft();
|
|
}
|
|
|
|
// Minimum von RTB gefunden
|
|
if (minimumParent != nullptr) {
|
|
minimumParent->setLeft(minimumRTB->getRight());
|
|
minimumRTB->setLeft(getAnker()->getLeft());
|
|
minimumRTB->setRight(getAnker()->getRight());
|
|
}
|
|
|
|
// Minimum von RTB ist RTB-Wurzel (RTB->left == nullptr)
|
|
else
|
|
minimumRTB->setLeft(getAnker()->getLeft());
|
|
|
|
delete getAnker();
|
|
setAnker(minimumRTB);
|
|
cout << "+ Datensatz wurde gelöscht.\n";
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Loeschen von Nodes - Node != Wurzel
|
|
else {
|
|
// zu loeschende Node und Parent_Node
|
|
TreeNode* ptr = getAnker();
|
|
TreeNode* parent = getAnker();
|
|
|
|
// suche zuloeschenden Node
|
|
while ((ptr->getRight() || ptr->getLeft()) && ptr->getNodeOrderID() != delNodeID && ptr) {
|
|
parent = ptr;
|
|
delNodeID < ptr->getNodeOrderID() ?
|
|
ptr = ptr->getLeft() : ptr = ptr->getRight();
|
|
}
|
|
|
|
// 1. Fall Loeschen von Nodes - ohne Nachfolger
|
|
if (!ptr->getRight() && !ptr->getLeft()) {
|
|
parent->getNodeOrderID() < ptr->getNodeOrderID() ?
|
|
parent->setRight(nullptr) : parent->setLeft(nullptr);
|
|
delete ptr;
|
|
cout << "+ Datensatz wurde gelöscht.\n";
|
|
return true;
|
|
}
|
|
|
|
// 2. Fall Loeschen von Nodes - mit einem Nachfolger
|
|
else if ((!ptr->getRight() && ptr->getLeft()) || (ptr->getRight() && !ptr->getLeft())) {
|
|
if (parent->getNodeOrderID() < ptr->getNodeOrderID())
|
|
ptr->getRight() ?
|
|
parent->setRight(ptr->getRight()) : parent->setRight(ptr->getLeft());
|
|
else
|
|
ptr->getRight() ?
|
|
parent->setLeft(ptr->getRight()) : parent->setLeft(ptr->getLeft());
|
|
|
|
delete ptr;
|
|
cout << "+ Datensatz wurde gelöscht.\n";
|
|
return true;
|
|
}
|
|
|
|
// 3. Fall Loeschen von Nodes - mit zwei Nachfolger
|
|
if (ptr->getRight() != nullptr && ptr->getLeft() != nullptr) {
|
|
TreeNode* minimumRTB = ptr->getRight();
|
|
TreeNode* minimumParent = nullptr;
|
|
|
|
//Minumum von RTB suchen.
|
|
while (minimumRTB->getLeft() != nullptr) {
|
|
minimumParent = minimumRTB;
|
|
minimumRTB = minimumRTB->getLeft();
|
|
}
|
|
|
|
//Minimum von RTB gefunden
|
|
if (minimumParent != nullptr) {
|
|
minimumParent->setLeft(minimumRTB->getRight());
|
|
minimumRTB->setLeft(ptr->getLeft());
|
|
minimumRTB->setRight(ptr->getRight());
|
|
}
|
|
|
|
//Minimum von RTB ist RTB-Wurzel (RTB->left == nullptr)
|
|
else
|
|
minimumRTB->setLeft(ptr->getLeft());
|
|
|
|
//verknuepfe parent von zu loeschende Node
|
|
parent->getNodeOrderID() < ptr->getNodeOrderID() ?
|
|
parent->setRight(minimumRTB) :
|
|
parent->setLeft(minimumRTB);
|
|
|
|
delete ptr;
|
|
cout << "+ Datensatz wurde gelöscht.\n";
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Tree::searchNode(std::string name) {
|
|
|
|
// Baum muss vorhanden sein
|
|
if (getAnker() != nullptr) {
|
|
bool found = false;
|
|
TreeNode* ptr = getAnker();
|
|
TreeNode* node;
|
|
|
|
cout << endl <<
|
|
"ID | Name | Alter | Einkommen | PLZ | OrderID\n"
|
|
"---+------------+-------+-----------+-------+--------\n";
|
|
|
|
queue<TreeNode*> q;
|
|
q.push(ptr);
|
|
while (!q.empty()) {
|
|
node = q.front();
|
|
q.pop();
|
|
if (node->getName() == name) {
|
|
printNode(node);
|
|
found = true;
|
|
// break; // damit werden alle Knoten mit dem Namen ausgegeben
|
|
}
|
|
if (node->getLeft() != nullptr)
|
|
q.push(node->getLeft());
|
|
if (node->getRight() != nullptr)
|
|
q.push(node->getRight());
|
|
}
|
|
|
|
if (!found)
|
|
cout << "--------------- Kein Eintrag vorhanden --------------" << endl;
|
|
return found;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Tree::printNode(TreeNode* node) {
|
|
cout << setw(3) << node->getNodeChronologicalID() << '|' << setw(12) << node->getName() << '|'
|
|
<< setw(7) << node->getAge() << '|' << setw(11) << node->getIncome() << '|'
|
|
<< setw(7) << node->getPostCode() << '|' << setw(8) << node->getNodeOrderID() << endl;
|
|
}
|
|
|
|
void Tree::printLevelOrder() {
|
|
|
|
TreeNode* root = getAnker();
|
|
|
|
// 2 Queues instanzieren
|
|
std::queue<TreeNode*> q;
|
|
std::queue<int> nq;
|
|
|
|
cout << endl <<
|
|
"ID | Name | Alter | Einkommen | PLZ | OrderID\n"
|
|
"---+------------+-------+-----------+-------+--------\n";
|
|
|
|
if (root == nullptr) {
|
|
cout << "--------------- Kein Eintrag vorhanden --------------" << endl;
|
|
return;
|
|
}
|
|
|
|
// Wurzelknoten und Startniveau in die Queues pushen
|
|
q.push(root);
|
|
nq.push(0);
|
|
|
|
// vorheriges Niveau merken bzw. den Niveauwechsel irgendwie mitbekommen
|
|
int prev_niveau = -1;
|
|
int niveau;
|
|
|
|
// Schleife
|
|
while (!q.empty()) {
|
|
// Entnahme aus den Queues und loeschen
|
|
TreeNode* ptr = q.front();
|
|
q.pop();
|
|
niveau = nq.front();
|
|
nq.pop();
|
|
|
|
// Ausgabe Niveauwechsel
|
|
if (prev_niveau != niveau) {
|
|
std::cout << std::endl << "Niveau " << niveau << ": " << endl;
|
|
prev_niveau = niveau;
|
|
}
|
|
// Ausgabe des Knotens
|
|
printNode(ptr);
|
|
|
|
// Linker Nachfolgeknoten in die Queues
|
|
if (ptr->getLeft() != nullptr) {
|
|
q.push(ptr->getLeft());
|
|
nq.push(niveau + 1);
|
|
}
|
|
// Rechter Nachfolgeknoten in die Queues
|
|
if (ptr->getRight() != nullptr) {
|
|
q.push(ptr->getRight());
|
|
nq.push(niveau + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Tree::printPreOrder(TreeNode* ptr) {
|
|
if (ptr != nullptr) {
|
|
printNode(ptr);
|
|
printPreOrder(ptr->getLeft());
|
|
printPreOrder(ptr->getRight());
|
|
}
|
|
}
|
|
|
|
void Tree::printPostOrder(TreeNode* ptr) {
|
|
if (ptr != nullptr) {
|
|
printPreOrder(ptr->getLeft());
|
|
printPreOrder(ptr->getRight());
|
|
printNode(ptr);
|
|
}
|
|
}
|
|
|
|
void Tree::printInOrder(TreeNode* ptr) {
|
|
if (ptr != nullptr) {
|
|
printPreOrder(ptr->getLeft());
|
|
printNode(ptr);
|
|
printPreOrder(ptr->getRight());
|
|
}
|
|
}
|
|
|
|
|
|
void Tree::printAll() {
|
|
if (getAnker() != nullptr) {
|
|
string ausgabeFormat;
|
|
cout << "Ausgabereihenfolge ?> ";
|
|
cin >> ausgabeFormat;
|
|
TreeNode* ptr = getAnker();
|
|
cout << endl <<
|
|
"ID | Name | Alter | Einkommen | PLZ | OrderID\n"
|
|
"---+------------+-------+-----------+-------+--------\n";
|
|
if (ausgabeFormat == "pre")
|
|
printPreOrder(getAnker());
|
|
|
|
else if (ausgabeFormat == "post")
|
|
printPostOrder(getAnker());
|
|
|
|
else if (ausgabeFormat == "in")
|
|
printInOrder(getAnker());
|
|
|
|
else
|
|
cout << "falsches Formatkürzel";
|
|
|
|
}
|
|
else
|
|
cout << "--------------- Kein Eintrag vorhanden --------------\n";
|
|
} |