mirror of
https://github.com/tiennm99/HCMUT.git
synced 2026-10-14 06:17:57 +00:00
Update Lab6
This commit is contained in:
1 parent
f966748502
commit
f8418fa0e6
5 files changed
+553
No files matched your search
@@ -0,0 +1,92 @@
|
||||
#ifndef AVLNODE_H
|
||||
#define AVLNODE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <class T>
|
||||
class AVLNode
|
||||
{
|
||||
public:
|
||||
T data;
|
||||
int balance = 0;
|
||||
int height = 1;
|
||||
AVLNode *parent = nullptr;
|
||||
AVLNode *left = nullptr;
|
||||
AVLNode *right = nullptr;
|
||||
AVLNode();
|
||||
AVLNode(T data);
|
||||
~AVLNode();
|
||||
void update();
|
||||
void print(int space);
|
||||
template <class U>
|
||||
friend ostream &operator << (ostream &os, AVLNode<U> *node);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
AVLNode<T>::AVLNode()
|
||||
{
|
||||
this->balance = 0;
|
||||
this->height = 1;
|
||||
this->parent = nullptr;
|
||||
this->left = nullptr;
|
||||
this->right = nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLNode<T>::AVLNode(T data)
|
||||
{
|
||||
this->data = data;
|
||||
this->balance = 0;
|
||||
this->height = 1;
|
||||
this->parent = nullptr;
|
||||
this->left = nullptr;
|
||||
this->right = nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLNode<T>::~AVLNode()
|
||||
{
|
||||
this->parent = nullptr;
|
||||
delete this->left;
|
||||
this->left = nullptr;
|
||||
delete this->right;
|
||||
this->right = nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLNode<T>::update()
|
||||
{
|
||||
int hl = 0;
|
||||
int hr = 0;
|
||||
if (this->left != nullptr)
|
||||
hl = this->left->height;
|
||||
if (this->right != nullptr)
|
||||
hr = this->right->height;
|
||||
this->height = max(hl, hr) + 1;
|
||||
this->balance = hl - hr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLNode<T>::print(int space)
|
||||
{
|
||||
if (space < 0)
|
||||
return;
|
||||
for (int i = 0; i < space - this->height; ++i)
|
||||
cout << "\t";
|
||||
this->print();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ostream &operator << (ostream &os, AVLNode<T> *node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return os;
|
||||
os << node->left;
|
||||
os << node->data;
|
||||
os << node->right;
|
||||
return os;
|
||||
}
|
||||
|
||||
#endif // AVLNODE_H
|
||||
@@ -0,0 +1,262 @@
|
||||
#ifndef AVLTREE_H
|
||||
#define AVLTREE_H
|
||||
|
||||
#include <stack>
|
||||
#include "avlnode.h"
|
||||
|
||||
template <class T>
|
||||
class AVLTree
|
||||
{
|
||||
private:
|
||||
AVLNode<T> *root = nullptr;
|
||||
AVLNode<T> *rotateLeft(AVLNode<T> *node);
|
||||
AVLNode<T> *rotateRight(AVLNode<T> *node);
|
||||
int getHeight(AVLNode<T> *node);
|
||||
void rebalance(AVLNode<T> *node);
|
||||
public:
|
||||
AVLTree();
|
||||
~AVLTree();
|
||||
bool insert(AVLNode<T> *newNode);
|
||||
AVLNode<T> *search(T searchData);
|
||||
bool remove(const T removeData);
|
||||
void printAsList();
|
||||
void printNLR();
|
||||
template <class U>
|
||||
friend ostream &operator << (ostream &os, AVLTree<U> *tree);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
AVLTree<T>::AVLTree()
|
||||
{
|
||||
this->root = nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLTree<T>::~AVLTree()
|
||||
{
|
||||
delete this->root;
|
||||
this->root = nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLTree<T>::rebalance(AVLNode<T> *node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return;
|
||||
node->update();
|
||||
if (node->balance > 1) {
|
||||
if (node->left->balance < -1)
|
||||
node->left = rotateLeft(node->left);
|
||||
node = rotateRight(node);
|
||||
} else if (node->balance < -1) {
|
||||
if (node->right->balance > 1)
|
||||
node->right = rotateRight(node->right);
|
||||
node = rotateLeft(node);
|
||||
}
|
||||
if (node->parent == nullptr)
|
||||
this->root = node;
|
||||
else
|
||||
rebalance(node->parent);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLNode<T> *AVLTree<T>::rotateLeft(AVLNode<T> *node)
|
||||
{
|
||||
AVLNode<T> *temp = node->right;
|
||||
AVLNode<T> *tmp = temp->left;
|
||||
AVLNode<T> *parent = node->parent;
|
||||
temp->parent = parent;
|
||||
node->right = tmp;
|
||||
if (tmp != nullptr) {
|
||||
tmp->parent = node;
|
||||
}
|
||||
temp->left = node;
|
||||
node->parent = temp;
|
||||
if (parent != nullptr) {
|
||||
if (parent->left == node)
|
||||
parent->left = temp;
|
||||
else
|
||||
parent->right = temp;
|
||||
}
|
||||
node->update();
|
||||
temp->update();
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLNode<T> *AVLTree<T>::rotateRight(AVLNode<T> *node)
|
||||
{
|
||||
AVLNode<T> *temp = node->left;
|
||||
AVLNode<T> *tmp = temp->right;
|
||||
AVLNode<T> *parent = node->parent;
|
||||
temp->parent = parent;
|
||||
node->left = tmp;
|
||||
if (tmp != nullptr) {
|
||||
tmp->parent = node;
|
||||
}
|
||||
temp->right = node;
|
||||
node->parent = temp;
|
||||
if (parent != nullptr) {
|
||||
if (parent->left == node)
|
||||
parent->left = temp;
|
||||
else
|
||||
parent->right = temp;
|
||||
}
|
||||
node->update();
|
||||
temp->update();
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int AVLTree<T>::getHeight(AVLNode<T> *node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return 0;
|
||||
return node->height;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool AVLTree<T>::insert(AVLNode<T> *newNode)
|
||||
{
|
||||
if (newNode == nullptr)
|
||||
return false;
|
||||
if (this->root == nullptr) {
|
||||
this->root = newNode;
|
||||
return true;
|
||||
}
|
||||
AVLNode<T> *temp = this->root;
|
||||
AVLNode<T> *parent;
|
||||
while (true) {
|
||||
if (temp->data == newNode->data)
|
||||
return false;
|
||||
parent = temp;
|
||||
bool goLeft = (newNode->data < temp->data);
|
||||
temp = goLeft ? temp->left : temp->right;
|
||||
if (temp == nullptr) {
|
||||
if (goLeft) {
|
||||
parent->left = newNode;
|
||||
newNode->parent = parent;
|
||||
} else {
|
||||
parent->right = newNode;
|
||||
newNode->parent = parent;
|
||||
}
|
||||
rebalance(parent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool AVLTree<T>::remove(const T removeData)
|
||||
{
|
||||
AVLNode<T> *temp = this->root;
|
||||
while (temp != nullptr) {
|
||||
if (removeData < temp->data)
|
||||
temp = temp->left;
|
||||
else if (removeData > temp->data)
|
||||
temp = temp->right;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (temp == nullptr)
|
||||
return false;
|
||||
AVLNode<T> *del = temp;
|
||||
if (temp->left != nullptr) {
|
||||
del = temp->left;
|
||||
while (del->right != nullptr)
|
||||
del = del->right;
|
||||
}
|
||||
AVLNode<T> *parent = nullptr;
|
||||
if (del == this->root) {
|
||||
this->root = this->root->right;
|
||||
if (this->root != nullptr)
|
||||
this->root->parent = nullptr;
|
||||
} else if (del != temp) {
|
||||
temp->data = del->data;
|
||||
parent = del->parent;
|
||||
if (parent->left == del)
|
||||
parent->left = del->left;
|
||||
else
|
||||
parent->right = del->left;
|
||||
if (del->left != nullptr)
|
||||
del->left->parent = parent;
|
||||
} else {
|
||||
parent = del->parent;
|
||||
if (parent->left == del)
|
||||
parent->left = del->right;
|
||||
else
|
||||
parent->right = del->right;
|
||||
if (del->right != nullptr)
|
||||
del->right->parent = parent;
|
||||
}
|
||||
if (parent != nullptr)
|
||||
this->rebalance(parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLTree<T>::printNLR()
|
||||
{
|
||||
stack<AVLNode<T> *> sAVLNode;
|
||||
stack<int> sNodeLevel;
|
||||
sAVLNode.push(this->root);
|
||||
sNodeLevel.push(0);
|
||||
while (!sAVLNode.empty()) {
|
||||
AVLNode<T> *tNode = sAVLNode.top();
|
||||
sAVLNode.pop();
|
||||
int tLevel = sNodeLevel.top();
|
||||
sNodeLevel.pop();
|
||||
for (int i = 0; i < tLevel; ++i) {
|
||||
cout << " ";
|
||||
}
|
||||
if (tNode == nullptr) {
|
||||
cout << "NULL" << endl;
|
||||
continue;
|
||||
}
|
||||
cout << tNode->data << "(" << tNode->balance << ")" << endl;
|
||||
sAVLNode.push(tNode->right);
|
||||
sNodeLevel.push(tLevel + 1);
|
||||
sAVLNode.push(tNode->left);
|
||||
sNodeLevel.push(tLevel + 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLNode<T> *AVLTree<T>::search(T searchData)
|
||||
{
|
||||
AVLNode<T> *temp = this->root;
|
||||
while (temp != nullptr) {
|
||||
if (searchData < temp->data)
|
||||
temp = temp->left;
|
||||
else if (searchData > temp->data)
|
||||
temp = temp->right;
|
||||
else
|
||||
return temp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void printLNR(AVLNode<T> *subroot)
|
||||
{
|
||||
if (subroot == nullptr)
|
||||
return;
|
||||
printLNR(subroot->left);
|
||||
cout << subroot->data << endl;
|
||||
printLNR(subroot->right);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLTree<T>::printAsList()
|
||||
{
|
||||
printLNR(this->root);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ostream &operator << (ostream &os, AVLTree<T> *tree)
|
||||
{
|
||||
os << tree->root;
|
||||
return os;
|
||||
}
|
||||
|
||||
#endif // AVLTREE_H
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef LAB6_H
|
||||
#define LAB6_H
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "avltree.h"
|
||||
#include "phone.h"
|
||||
|
||||
AVLTree<Phone> *readPhoneFromFile(string filename)
|
||||
{
|
||||
AVLTree<Phone> *newTree = nullptr;
|
||||
ifstream file;
|
||||
file.open(filename, ios::in);
|
||||
if (!file.is_open()) {
|
||||
cout << "Can't open file!" << endl;
|
||||
} else {
|
||||
newTree = new AVLTree<Phone>;
|
||||
string line;
|
||||
while (getline(file, line)) {
|
||||
AVLNode<Phone> *newNode = new AVLNode<Phone>;
|
||||
string str;
|
||||
stringstream ss;
|
||||
ss.str(line);
|
||||
getline(ss, str, ',');
|
||||
newNode->data.name = str;
|
||||
getline(ss, str);
|
||||
newNode->data.number = str;
|
||||
newTree->insert(newNode);
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return newTree;
|
||||
}
|
||||
|
||||
void writePhoneToFile(string filename, AVLTree<Phone> *tree)
|
||||
{
|
||||
ofstream file;
|
||||
file.open(filename, ios::out);
|
||||
file << tree;
|
||||
file.close();
|
||||
}
|
||||
|
||||
void printMenu()
|
||||
{
|
||||
cout << "========MENU========" << endl;
|
||||
cout << "Enter your command:" << endl;
|
||||
cout << "1. Search phone with name." << endl;
|
||||
cout << "2. Insert new phone." << endl;
|
||||
cout << "3. Delete phone with name." << endl;
|
||||
cout << "4. Print phone list." << endl;
|
||||
cout << "0. Exit program." << endl;
|
||||
}
|
||||
|
||||
#endif // LAB6_H
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "lab6.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
string command = "";
|
||||
string filename = "phone.csv";
|
||||
AVLTree<Phone> *phoneTree = readPhoneFromFile(filename);
|
||||
if (phoneTree == nullptr)
|
||||
return 1;
|
||||
while (true) {
|
||||
system("clear"); // Clear terminal for Linux
|
||||
printMenu();
|
||||
getline(cin, command);
|
||||
if (command == "1") {
|
||||
cout << "Input full name:" << endl;
|
||||
string str = "";
|
||||
getline(cin, str);
|
||||
Phone searchData(str);
|
||||
AVLNode<Phone> *searchNode = phoneTree->search(searchData);
|
||||
if (searchNode == nullptr) {
|
||||
cout << "Can't file phone with this name!" << endl;
|
||||
} else {
|
||||
cout << searchNode->data.name << "'s number is " << searchNode->data.number << endl;
|
||||
}
|
||||
} else if (command == "2") {
|
||||
cout << "Input new name:" << endl;
|
||||
string str1 = "";
|
||||
getline(cin, str1);
|
||||
cout << "Input new number:" << endl;
|
||||
string str2 = "";
|
||||
getline(cin, str2);
|
||||
Phone newData(str1, str2);
|
||||
AVLNode<Phone> *newNode = new AVLNode<Phone>(newData);
|
||||
if (newNode == nullptr)
|
||||
cout << "Error! Out of memory!" << endl;
|
||||
else if (phoneTree->insert(newNode))
|
||||
cout << "Insert successful!" << endl;
|
||||
else
|
||||
cout << "Error! Duplicate name!" << endl;
|
||||
} else if (command == "3") {
|
||||
cout << "Input name to delete:" << endl;
|
||||
string str = "";
|
||||
getline(cin, str);
|
||||
Phone deleteData(str);
|
||||
if (phoneTree->remove(deleteData))
|
||||
cout << "Delete successful!" << endl;
|
||||
else
|
||||
cout << "Can't found this name! You must input full name!" << endl;
|
||||
} else if (command == "4") {
|
||||
cout << phoneTree;
|
||||
} else if (command == "0") {
|
||||
cout << "Good Bye!" << endl;
|
||||
break;
|
||||
} else {
|
||||
cout << "Invalid command!" << endl;
|
||||
}
|
||||
writePhoneToFile(filename, phoneTree);
|
||||
cout << "Press Enter to continue" << endl;
|
||||
cin.get();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef PHONE_H
|
||||
#define PHONE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Phone
|
||||
{
|
||||
public:
|
||||
string name = "";
|
||||
string number = "";
|
||||
Phone();
|
||||
Phone(string name);
|
||||
Phone(string name, string number);
|
||||
~Phone();
|
||||
friend bool operator < (const Phone &l, const Phone &r);
|
||||
friend bool operator > (const Phone &l, const Phone &r);
|
||||
friend bool operator == (const Phone &l, const Phone &r);
|
||||
friend bool operator <= (const Phone &l, const Phone &r);
|
||||
friend bool operator >= (const Phone &l, const Phone &r);
|
||||
friend ostream &operator << (ostream &os, const Phone &phone);
|
||||
};
|
||||
|
||||
Phone::Phone()
|
||||
{
|
||||
this->name = "";
|
||||
this->number = "";
|
||||
}
|
||||
|
||||
Phone::Phone(string name)
|
||||
{
|
||||
this->name = name;
|
||||
this->number = "";
|
||||
}
|
||||
|
||||
Phone::Phone(string name, string number)
|
||||
{
|
||||
this->name = name;
|
||||
this->number = number;
|
||||
}
|
||||
|
||||
Phone::~Phone()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
bool operator < (const Phone &l, const Phone &r)
|
||||
{
|
||||
return l.name < r.name;
|
||||
}
|
||||
|
||||
bool operator > (const Phone &l, const Phone &r)
|
||||
{
|
||||
return l.name > r.name;
|
||||
}
|
||||
|
||||
bool operator == (const Phone &l, const Phone &r)
|
||||
{
|
||||
return l.name == r.name;
|
||||
}
|
||||
|
||||
bool operator <= (const Phone &l, const Phone &r)
|
||||
{
|
||||
return l.name <= r.name;
|
||||
}
|
||||
|
||||
bool operator >= (const Phone &l, const Phone &r)
|
||||
{
|
||||
return l.name >= r.name;
|
||||
}
|
||||
|
||||
ostream &operator << (ostream &os, const Phone &phone)
|
||||
{
|
||||
os << phone.name << "," << phone.number << endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
#endif // PHONE_H
|
||||
Reference in new issue
Block a user