/************************************************* * ADS Praktikum 1.2 * Tree.cpp * Erweiterung um Hilfsfunktionen gestattet. *************************************************/ #include "Tree.h" #include "TreeNode.h" #include #include #include 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 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 q; std::queue 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"; }