This commit is contained in:
2025-02-21 13:17:35 +01:00
commit e6bb2d584f
135 changed files with 141834 additions and 0 deletions

BIN
P3/ADS_Praktikum_3.pdf Executable file

Binary file not shown.

12
P3/CMakeLists.txt Executable file
View File

@@ -0,0 +1,12 @@
# Set the minimum required version of CMake
cmake_minimum_required(VERSION 3.11)
# Set the project name and specify the C++ as the project language
project(P3_Binaerbaum)
# Specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Add an executable with the above sources
add_executable(P3_Binaerbaum main.cpp Tree.cpp TreeNode.cpp TreeTest.cpp)

18
P3/ExportZielanalyse.csv Executable file
View File

@@ -0,0 +1,18 @@
A;70;0;0
A;20;0;0
A;90;0;0
A;10;0;0
A;60;0;0
A;80;0;0
A;91;0;0
A;40;0;0
A;84;0;0
A;95;0;0
A;30;0;0
A;50;0;0
A;82;0;0
A;86;0;0
A;93;0;0
A;96;0;0
A;92;0;0
A;94;0;0
1 A 70 0 0
2 A 20 0 0
3 A 90 0 0
4 A 10 0 0
5 A 60 0 0
6 A 80 0 0
7 A 91 0 0
8 A 40 0 0
9 A 84 0 0
10 A 95 0 0
11 A 30 0 0
12 A 50 0 0
13 A 82 0 0
14 A 86 0 0
15 A 93 0 0
16 A 96 0 0
17 A 92 0 0
18 A 94 0 0

485
P3/Tree.cpp Executable file
View File

@@ -0,0 +1,485 @@
//
// Tree.cpp
// ADS P3
//
#include "Tree.h"
#include "TreeNode.h"
#include <iomanip>
#include <iostream>
#include <string>
#include <queue>
Tree::Tree() : m_anker{ nullptr }, m_currentNodeChronologicalID{ 0 } {}
Tree::~Tree() {
deleteAll(m_anker);
}
void Tree::deleteAll(TreeNode* _anker) {
if (_anker != nullptr) {
deleteAll(_anker->getLeft());
deleteAll(_anker->getRight());
delete _anker;
}
return;
}
bool Tree::isLeaf(TreeNode* _node) {
if (!_node->getLeft() && !_node->getRight())
return true;
return false;
}
void Tree::balance(TreeNode* node) {
TreeNode* ptr = node;
TreeNode* par = ptr->getParent();
while (par) {
// parent & ptr sind rot
if (ptr->getRed() && par->getRed()) {
// Knoten ist links von parent
if (par->getLeft() == ptr) {
// parent ist links von grandparent
if (par->getParent()->getLeft() == par)
rotateTreeRight(par->getParent(), par);
// PP
// P
// ptr
else {
rotateTreeRight(par, ptr);
rotateTreeLeft(ptr->getParent(), ptr);
}
}
// Knoten ist rechts von parent
else {
// parent ist rechts von grandparent
if (par->getParent()->getRight() == par)
rotateTreeLeft(par->getParent(), par);
// PP
// p
// ptr
else {
rotateTreeLeft(par, ptr);
rotateTreeRight(ptr->getParent(), ptr);
}
}
}
ptr = par;
par = ptr->getParent();
}
return;
}
bool Tree::split4Node(TreeNode* node) {
TreeNode* left = node->getLeft();
TreeNode* right = node->getRight();
if (!node || node->getRed() || !left || !right)
return false;
else {
if (left->getRed() && right->getRed()) {
left->setRed(false);
right->setRed(false);
if (node != m_anker)
node->setRed(true);
return true;
}
}
return false;
}
void Tree::height() {
int proof = proofRBCriterion(m_anker);
if (proof == -1)
std::cout << "Error proofRBCriterion()" << std::endl;
else {
std::cout << std::endl
<< "Root has height: " << proof << std::endl;
}
}
int Tree::proofRBCriterion() {
return proofRBCriterion(this->m_anker);
}
int Tree::proofRBCriterion(TreeNode* node) {
if (!node)
return 0; // -1, da nicht existend
int left = proofRBCriterion(node->getLeft());
int right = proofRBCriterion(node->getRight());
// Fall 1: nur ein Nachfolger
if ((!node->getRight() && node->getLeft()) || (!node->getLeft() && node->getRight())) {
// Nachfolger ist rechts
if (node->getRight()) {
if (node->getRight()->getRed()) // roter Nachfolger ist auf dem selben Nivau
return right;
else // schwarzer Nachfolger ist ein Niveau tiefer
return ++right;
}
// Nachfolger ist links
else {
if (node->getLeft()->getRed()) // roter Nachfolger ist auf dem selben Nivau
return left;
else // schwarzer Nachfolger ist ein Niveau tiefer
return ++left;
}
}
// Fall 2-4: mit zwei Nachfolgern
else if (node->getRight() && node->getLeft()) {
// Fall 2: ein Nachfolger ist rot
if ((node->getLeft()->getRed() && !node->getRight()->getRed()) || (!node->getLeft()->getRed() && node->getRight()->getRed())) {
if (node->getLeft()->getRed() && left == right + 1) // links ist rot
return left;
else if (node->getRight()->getRed() && right == left + 1) // rechts ist rot
return right;
else // Fehler in der Zählung
return -1;
}
// Fall 3: beide Nachfolger sind rot => 4er Knoten
if (node->getLeft()->getRed() && node->getRight()->getRed()) {
if (left == right) // beide müssen auf dem selben Niveu sein
return left;
else // Fehler in der Zählung
return -1;
}
// Fall 5: beide Nachfolger sind schwarz
else {
if (left == right) // beide müssen auf dem selben Niveu sein
return ++left;
else
return -1;
}
}
// Fall 5: keine Nachfolger
else
return 0;
}
bool Tree::rotateTreeRight(TreeNode* _parent, TreeNode* _child) {
_parent->setLeft(_child->getRight());
if (_child->getRight())
_child->getRight()->setParent(_parent);
_child->setParent(_parent->getParent());
if (!_parent->getParent())
m_anker = _child;
else if (_parent == _parent->getParent()->getLeft())
_parent->getParent()->setLeft(_child);
else
_parent->getParent()->setRight(_child);
_child->setRight(_parent);
_child->setRed(false);
_parent->setParent(_child);
_parent->setRed(true);
return true;
}
bool Tree::rotateTreeLeft(TreeNode* _parent, TreeNode* _child) {
_parent->setRight(_child->getLeft());
if (_child->getLeft())
_child->getLeft()->setParent(_parent);
_child->setParent(_parent->getParent());
if (!_parent->getParent()) {
m_anker = _child;
}
else if (_parent == _parent->getParent()->getLeft()) {
_parent->getParent()->setLeft(_child);
}
else
_parent->getParent()->setRight(_child);
_child->setLeft(_parent);
_child->setRed(false);
_parent->setParent(_child);
_parent->setRed(true);
return true;
}
bool Tree::searchNode(std::string _name) {
bool found = false;
helpSearch(m_anker, _name, found);
if (!found)
std::cout << "+ Datensatz nicht gefunden." << std::endl;
return found;
}
void Tree::helpSearch(TreeNode* _anker, std::string _name, bool& _found) {
if (_anker != nullptr) {
if (_anker->getName() == _name) {
_found = true;
std::cout << "+ Fundstelle:";
printerHeader();
_anker->print();
}
helpSearch(_anker->getLeft(), _name, _found);
helpSearch(_anker->getRight(), _name, _found);
}
return;
}
bool Tree::addNode(std::string _name, int _age, double _income, int _postCode) {
TreeNode* leaf = new TreeNode(0, m_currentNodeChronologicalID, _name, _income, _postCode, _age);
m_currentNodeChronologicalID++;
if (m_anker == nullptr) {
leaf->setRed(false);
m_anker = leaf;
return true;
}
TreeNode* ptr = m_anker;
TreeNode* par = ptr;
while (ptr != nullptr) {
par = ptr;
split4Node(ptr);
if (leaf->getNodeOrderID() < ptr->getNodeOrderID())
ptr = ptr->getLeft();
else
ptr = ptr->getRight();
}
if (leaf->getNodeOrderID() < par->getNodeOrderID())
par->setLeft(leaf);
else
par->setRight(leaf);
leaf->setParent(par);
m_anker->setRed(false);
balance(leaf);
return true;
}
// Print Funktionen
void Tree::printAll() {
printerHeader();
printer(m_anker);
std::cout << "-----+-------------+-----+----------+----------+--------+" << std::endl;
height();
}
void Tree::printer(TreeNode* node) {
if (!node)
return;
node->print();
printer(node->getLeft());
printer(node->getRight());
return;
}
void Tree::printLevel(TreeNode* _anker) {
if (!_anker)
return;
if (!_anker->getRed())
_anker->print();
if (_anker->getLeft()) {
if (_anker->getLeft()->getRed())
_anker->getLeft()->print();
}
if (_anker->getRight()) {
if (_anker->getRight()->getRed())
_anker->getRight()->print();
}
printLevel(_anker->getLeft());
printLevel(_anker->getRight());
}
void Tree::printLevelOrder() {
std::cout << "Ausgabe in LevelOrder als Binaer Baum" << std::endl;
printerHeader();
printLevel(m_anker);
std::cout << "-----+-------------+-----+----------+----------+--------+" << std::endl;
std::cout << "Ausgabe in LevelOrder als 234-Tree: " << std::endl;
print234Tree();
height();
}
void Tree::printLevelOrder(int niveau) {
print234Tree(niveau);
}
void Tree::print234Tree() {
if (!m_anker)
return;
int niv = 0;
std::queue<int> nivQ;
std::queue<TreeNode*> nodeQ;
nodeQ.push(m_anker);
nivQ.push(niv);
std::cout << "Niveau " << niv << ":";
TreeNode* ptr;
int nivOut;
while (!nodeQ.empty()) {
ptr = nodeQ.front();
nivOut = nivQ.front();
nodeQ.pop();
nivQ.pop();
if (niv < nivOut) {
std::cout << std::endl
<< "Niveau " << nivOut << ":";
niv++;
}
std::cout << " (";
if (ptr->getLeft()) {
TreeNode* left = ptr->getLeft();
if (left->getRed()) {
if (left->getLeft()) {
nodeQ.push(left->getLeft());
nivQ.push(left->depth() + 1);
}
if (left->getRight()) {
nodeQ.push(left->getRight());
nivQ.push(left->depth() + 1);
}
left->printOrderID();
}
else {
nodeQ.push(left);
nivQ.push(left->depth());
}
}
ptr->printOrderID();
if (ptr->getRight()) {
TreeNode* right = ptr->getRight();
if (right->getRed()) {
if (right->getLeft()) {
nodeQ.push(right->getLeft());
nivQ.push(right->depth() + 1);
}
if (right->getRight()) {
nodeQ.push(right->getRight());
nivQ.push(right->depth() + 1);
}
right->printOrderID();
}
else {
nodeQ.push(right);
nivQ.push(right->depth());
}
}
std::cout << ")";
}
}
void Tree::print234Tree(int niveau) {
if (!m_anker)
return;
int niv = 0;
std::queue<int> nivQ;
std::queue<TreeNode*> nodeQ;
nodeQ.push(m_anker);
nivQ.push(niv);
TreeNode* ptr;
int nivOut;
while (!nodeQ.empty()) {
ptr = nodeQ.front();
nivOut = nivQ.front();
nodeQ.pop();
nivQ.pop();
if (niveau + 1 == nivOut)
return;
if (niv < nivOut) {
if (nivOut == niveau)
std::cout << std::endl << "Niveau " << niveau << ":";
niv++;
}
if (niv == niveau && niveau == 0)
std::cout << std::endl << "Niveau " << niveau << ":";
if (niv == niveau)
std::cout << " (";
if (ptr->getLeft()) {
TreeNode* left = ptr->getLeft();
if (left->getRed()) {
if (left->getLeft()) {
nodeQ.push(left->getLeft());
nivQ.push(left->depth() + 1);
}
if (left->getRight()) {
nodeQ.push(left->getRight());
nivQ.push(left->depth() + 1);
}
if (niv == niveau)
left->printOrderID();
}
else {
nodeQ.push(left);
nivQ.push(left->depth());
}
}
if (niv == niveau)
ptr->printOrderID();
if (ptr->getRight()) {
TreeNode* right = ptr->getRight();
if (right->getRed()) {
if (right->getLeft()) {
nodeQ.push(right->getLeft());
nivQ.push(right->depth() + 1);
}
if (right->getRight()) {
nodeQ.push(right->getRight());
nivQ.push(right->depth() + 1);
}
if (niv == niveau)
right->printOrderID();
}
else {
nodeQ.push(right);
nivQ.push(right->depth());
}
}
if (niv == niveau)
std::cout << ")";
}
std::cout << std::endl << std::endl;
}
void Tree::printerHeader() {
std::cout << std::endl;
std::cout.width(5);
std::cout << "ID"
<< "|";
std::cout.width(13);
std::cout << "Name"
<< "|";
std::cout.width(5);
std::cout << "Age"
<< "|";
std::cout.width(10);
std::cout << "Income"
<< "|";
std::cout.width(10);
std::cout << "PostCode"
<< "|";
std::cout.width(8);
std::cout << "OrderID"
<< "|" << std::endl;
std::cout << "-----+-------------+-----+----------+----------+--------+" << std::endl;
}

49
P3/Tree.h Executable file
View File

@@ -0,0 +1,49 @@
//
// Tree.hpp
// ADS P3
//
#pragma once
#include "TreeNode.h"
#include <string>
class Tree {
private:
TreeNode* m_anker;
int m_currentNodeChronologicalID;
void deleteAll(TreeNode* _anker);
bool isLeaf(TreeNode* _node);
void balance(TreeNode* _node);
bool split4Node(TreeNode* _node);
void height();
bool rotateTreeRight(TreeNode*, TreeNode*);
bool rotateTreeLeft(TreeNode*, TreeNode*);
void helpSearch(TreeNode* _anker, std::string _name, bool& _found);
void printerHeader();
void printer(TreeNode* _anker);
void printLevel(TreeNode* _anker);
public:
Tree();
~Tree();
int proofRBCriterion();
int proofRBCriterion(TreeNode*);
bool addNode(std::string _name, int _age, double _income, int _postCode);
bool searchNode(std::string _name);
void printAll(void);
void print234Tree();
void print234Tree(int niveau);
void printLevelOrder();
void printLevelOrder(int niveau);
// friend-Funktionen sind für die Tests erforderlich und müssen unangetastet
// bleiben!
friend TreeNode* get_anker(Tree& TN);
};

67
P3/TreeNode.cpp Executable file
View File

@@ -0,0 +1,67 @@
//
// TreeNode.cpp
// ADS P3
//
#include "TreeNode.h"
#include <iostream>
#include <string>
TreeNode::TreeNode(int _nodeOrderID, int _nodeChronologicalID, std::string _name, double _income, int _postCode, int _age) :
m_NodeChronologicalID{ _nodeChronologicalID },
m_Name{ _name },
m_Age{ _age },
m_Income{ _income },
m_PostCode{ _postCode },
red{ true } {
m_NodeOrderID = m_Age + m_PostCode + int(m_Income);
m_left = nullptr;
m_right = nullptr;
m_parent = nullptr;
}
TreeNode::~TreeNode() {
}
void TreeNode::print() {
std::cout.width(5);
std::cout << this->getNodeChronologicalID() << "|";
std::cout.width(13);
std::cout << this->getName() << "|";
std::cout.width(5);
std::cout << this->getAge() << "|";
std::cout.width(10);
std::cout << this->getIncome() << "|";
std::cout.width(10);
std::cout << this->getPostCode() << "|";
std::cout.width(8);
std::cout << this->getNodeOrderID() << "|" << std::endl;
}
void TreeNode::printOrderID() {
std::cout << " " << m_NodeOrderID << " ";
}
void TreeNode::setRed(bool _red) {
if (this != nullptr)
red = _red;
return;
}
bool TreeNode::getRed() {
if (this)
return red;
else
return false;
}
int TreeNode::depth() {
TreeNode* ptr = this;
int depth = 0;
while (ptr != nullptr) {
if (!ptr->getRed()) depth++;
ptr = ptr->getParent();
}
return depth - 1;
}

63
P3/TreeNode.h Executable file
View File

@@ -0,0 +1,63 @@
//
// TreeNode.hpp
// ADS P3
//
#pragma once
#include <string>
using namespace std;
class TreeNode {
private:
int m_NodeOrderID;
int m_NodeChronologicalID;
std::string m_Name;
int m_Age;
double m_Income;
int m_PostCode;
TreeNode* m_left;
TreeNode* m_right;
TreeNode* m_parent;
bool red;
public:
TreeNode(int, int, std::string, double, int, int _age = 1);
~TreeNode();
int getNodeOrderID() { return m_NodeOrderID; }
void setNodeOderID(int _id) { m_NodeOrderID = _id; }
int getNodeChronologicalID() { return m_NodeChronologicalID; }
void setNodeChronologicalID(int _id) { m_NodeChronologicalID = _id; }
std::string getName() { return m_Name; }
void setName(std::string _name) { m_Name = _name; }
int getAge() { return m_Age; }
void setAge(int _age) { m_Age = _age; }
double getIncome() { return m_Income; }
void setIncome(double _income) { m_Income = _income; }
int getPostCode() { return m_PostCode; }
void setPostCode(int _postCode) { m_PostCode = _postCode; }
bool getRed();
void setRed(bool _red);
TreeNode* getLeft() { return m_left; }
void setLeft(TreeNode* _left) { m_left = _left; }
TreeNode* getRight() { return m_right; }
void setRight(TreeNode* _right) { m_right = _right; }
TreeNode* getParent() { return m_parent; }
void setParent(TreeNode* _parent) { m_parent = _parent; }
int depth();
void printOrderID();
void print();
};

484
P3/TreeTest.cpp Executable file

File diff suppressed because one or more lines are too long

18182
P3/catch.h Executable file

File diff suppressed because it is too large Load Diff

107
P3/main.cpp Executable file
View File

@@ -0,0 +1,107 @@
//
// main.cpp
// ADS P3
//
#define CATCH_CONFIG_RUNNER
#include "Tree.h"
#include "catch.h"
#include <iostream>
#include <fstream>
void mainscreen_addTreeCSV(Tree*& ref) {
char response;
cout << "+ Moechten Sie die Daten aus der Datei ExportZielanalyse.csv "
"importieren(j / n) \n?> ";
cin >> response;
if (response == 'j') {
ifstream csvread;
csvread.open("../ExportZielanalyse.csv", ios::in);
if (!csvread.is_open()) {
cout << "Fehler beim Lesen!" << endl;
return;
}
else {
string name, age, postcode, income;
while (!csvread.eof()) {
getline(csvread, name, ';');
getline(csvread, age, ';');
getline(csvread, income, ';');
getline(csvread, postcode, '\n');
ref->addNode(name, stoi(age), stod(income), stoi(postcode));
}
csvread.close();
}
cout << "+ Daten wurden dem Baum hinzugefuegt." << endl;
}
}
int main() {
int result = Catch::Session().run();
Tree* m_Baum = new Tree();
int engb;
while (true) {
cout << "====================================\n"
"1) Datensatz einfuegen, manuell\n"
"2) Datensatz einfuegen, CSV Datei\n"
"3) Suchen\n"
"4) Ausgabe in Levelorder\n"
"5) Ausgabe in Levelorder (mit Niveauauswahl)\n"
"6) Beenden\n"
"?> ";
cin >> engb;
switch (engb) {
case 1: {
string name;
int alter, plz;
double einkommen;
cout << "\n+ Bitte geben Sie die den Datensatz ein"
"\nName \n?> ";
cin >> name;
cout << "\nAlter \n?> ";
cin >> alter;
cout << "\nEinkommen \n?> ";
cin >> einkommen;
cout << "\nPLZ \n?> ";
cin >> plz;
m_Baum->addNode(name, alter, einkommen, plz);
cout << "\n+ Ihr Datensatz wurde eingefuegt" << endl;
break;
}
case 2: {
mainscreen_addTreeCSV(m_Baum);
break;
}
case 3: {
string name;
cout << "+ Bitte geben Sie den zu suchenden Datensatz an\n"
"Name ?> ";
cin >> name;
cout << "+ Fundstellen:\n";
m_Baum->searchNode(name);
break;
}
case 4: {
m_Baum->printLevelOrder();
break;
}
case 5: {
int niveau;
cout << "\n+ Bitte geben Sie das Niveau ein"
"\nNiveau \n?> ";
cin >> niveau;
m_Baum->print234Tree(niveau);
break;
}
case 6: {
return 0;
}
}
};
return 0;
}