diff --git a/tree.cpp b/tree.cpp index b5dbe81..e4bd95d 100644 --- a/tree.cpp +++ b/tree.cpp @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include template struct Node; @@ -13,6 +15,7 @@ template struct Node{ T value; int max_depth; + int inbalance; Node_ptr small; Node_ptr big; @@ -20,19 +23,32 @@ struct Node{ bool add_to_child(Node_ptr* child, T val); void update_depth(); void dump(std::ofstream& ofs) const; - Node(T v): value{v}, max_depth{0}, small{nullptr}, big{nullptr}{} + Node(T v): value{v}, max_depth{0}, inbalance{0}, small{nullptr}, big{nullptr}{} }; + + + template class Tree{ Node_ptr root; + Node_ptr* find(T val); bool try_to_del(Node_ptr* node, T val); + bool try_to_add(Node_ptr* node, T val); + void rotate_left(Node_ptr* root); + void rotate_right(Node_ptr* root); + void balance(Node_ptr* n); + + bool test_insert(); + bool test_del(); + bool test_depth(Node_ptr* n); public: bool insert(T val); bool del(T val); void print() const; + bool test(); }; template @@ -47,37 +63,31 @@ Node_ptr* Tree::find(T val){ template bool Tree::insert(T val){ - if(!root){ - root = std::make_unique>(val); - return true; - } - else return root->add(val); + return try_to_add(&root, val); } template -bool Node::add(T val){ - if (val == value) return false; - else if (val < value) return add_to_child(&small, val); - else return add_to_child(&big, val); -} - -template -bool Node::add_to_child(Node_ptr* child, T val){ - if(!(*child)){ - *child = std::make_unique>(val); - update_depth(); +bool Tree::try_to_add(Node_ptr* node, T val){ + if( ! (*node)){ + *node = std::make_unique>(val); + (*node)->update_depth(); + balance(node); return true; } else{ - if((*child)->add(val)){ - update_depth(); - return true; + if (val == (*node)->value) return false; + else if(val < (*node)->value){ + if( ! try_to_add( &(*node)->small, val)) return false; } - return false; + else{//(val > (*node)->value) + if( ! try_to_add( &(*node)->big, val)) return false; + } + (*node)->update_depth(); + balance(node); + return true; } } - template bool Tree::del(T val){ if(!root) return false; @@ -91,7 +101,6 @@ bool Tree::try_to_del(Node_ptr* node, T val){ std::vector*> path; if((*node)->small) { path.push_back(temp); - std::cout << "pushing " << (*temp)->value << "\n"; temp = &(*node)->small; } else { @@ -100,7 +109,6 @@ bool Tree::try_to_del(Node_ptr* node, T val){ } while((*temp)->big){ path.push_back(temp); - std::cout << "pushing " << (*temp)->value << "\n"; temp = &(*temp)->big; } //mam temp na 'to swap' nodu... @@ -115,6 +123,7 @@ bool Tree::try_to_del(Node_ptr* node, T val){ else { if(try_to_del(&(*node)->small, val)){ (*node)->update_depth(); + balance(node); return true; } return false; @@ -125,6 +134,7 @@ bool Tree::try_to_del(Node_ptr* node, T val){ else { if(try_to_del(&(*node)->big, val)){ (*node)->update_depth(); + balance(node); return true; } return false; @@ -133,22 +143,37 @@ bool Tree::try_to_del(Node_ptr* node, T val){ } template -void Node::update_depth(){ - if(small && big) max_depth = std::max(small->max_depth, big->max_depth) + 1; - else if (small) max_depth = small->max_depth + 1; - else if (big) max_depth = big->max_depth + 1; - else max_depth = 0; +void Tree::rotate_left(Node_ptr* root){ + Node* new_root = (*root)->big.release(); + std::swap((*root)->big, new_root->small); + new_root->small.reset(root->release()); + root->reset(new_root); + + if((*root)->small) (*root)->small->update_depth(); + (*root)->update_depth(); } template -void Node::dump(std::ofstream& ofs) const { - if (small) { - ofs << '"' << value << " : " << max_depth << '"' << " -> " << '"' << small->value << " : " << small->max_depth << '"' << '\n'; - small->dump(ofs); +void Tree::rotate_right(Node_ptr* root){ + Node* new_root = (*root)->small.release(); + std::swap((*root)->small, new_root->big); + new_root->big.reset(root->release()); + root->reset(new_root); + + if( (*root)->big) (*root)->big->update_depth(); + (*root)->update_depth(); +} + +template +void Tree::balance(Node_ptr* n){ + if((*n)->inbalance >= -1 && (*n)->inbalance <= 1) return; + else if ((*n)->inbalance > 1){ + if((*n)->big && (*n)->big->inbalance == -1) rotate_right(&(*n)->big) ; + rotate_left(n) ; } - if (big) { - ofs << '"' << value << " : " << max_depth << '"' << " -> " << '"' << big->value << " : " << big->max_depth << '"' << '\n'; - big->dump(ofs); + else{ + if((*n)->small && (*n)->small->inbalance == 1) rotate_left(&(*n)->small); + rotate_right(n) ; } } @@ -164,17 +189,155 @@ void Tree::print() const { system("cat viz.dot | dot -Tx11"); } +template +bool Tree::test(){ + //vect s opak cisly, zkusim vlozit do stromu i setu a porovnam success, zkontroluju hloubky + root.reset(); + bool ins = test_insert(); + bool depth = test_depth(&root); + bool del = test_del(); + + std::cout << "--- INSERTING ---" << "\n"; + if(ins) std::cout << "\033[92m" << "\t\t" << "... done" << "\033[0m" << "\n"; + else std::cout << "\033[91m" << "\t\t" << "... wrong" << "\033[0m" << "\n"; + + std::cout << "--- CHECKING DEPTHS ---" << "\n"; + if(depth) std::cout << "\033[92m" << "\t\t" << "... done" << "\033[0m" << "\n"; + else std::cout << "\033[91m" << "\t\t" << "... wrong" << "\033[0m" << "\n"; + + std::cout << "--- EREASING ---" << "\n"; + if(del) std::cout << "\033[92m" << "\t\t" << "... done" << "\033[0m" << "\n"; + else std::cout << "\033[91m" << "\t\t" << "... wrong" << "\033[0m" << "\n"; + + root.reset(); + return ins && depth && del; +} + +template +bool Tree::test_insert(){ + root.reset(); + std::vector vec; + for(int i = 0; i < 10000000; i++){ + srand(i*3); + vec.push_back((rand() % 20000) - 9999); + } + + std::set set; + size_t prev_set_size = 0; + bool tree_ins; + // std::cout << "--- FILLING UP ---\n"; + for(int i = 0; i < 10000000; i++){ + set.insert(vec[i]); + tree_ins = insert(vec[i]); + if(tree_ins && set.size() == prev_set_size){ + // std::cout << "falsely inserted! \n"; + return false; + } + else if(!tree_ins && set.size() != prev_set_size){ + // std::cout << "skipped insert! \n"; + return false; + } + else prev_set_size = set.size(); + } + return true; +} + +template +bool Tree::test_del(){ + root.reset(); + std::vector vec; + std::set set; + for(int i = 0; i < 10000000; i++){ + srand(10000000-i); + vec.push_back((rand() % 20000) - 9999); + set.insert ((rand() % 20000) - 9999); + insert ((rand() % 20000) - 9999); + } + bool set_del; + bool tree_del; + // std::cout << "--- EMPTYING ---\n"; + for(int i = 0; i < 10000000; i++){ + tree_del = del(vec[i]); + set_del = set.erase(vec[i]); + if(tree_del && !set_del){ + // std::cout << "falsely deleted! \n"; + return false; + } + if(!tree_del && set_del){ + // std::cout << "skipped delete! \n"; + return false; + } + } + return true; +} + +template +bool Tree::test_depth(Node_ptr* n){ + if((*n)->small && (*n)->big){ + return test_depth(&(*n)->small) && + test_depth(&(*n)->big) && + (*n)->max_depth == ( std::max((*n)->small->max_depth, (*n)->big->max_depth) + 1 ); + } + else if((*n)->small){ + return test_depth(&(*n)->small) && + (*n)->max_depth == (*n)->small->max_depth + 1; + } + else if((*n)->big){ + return test_depth(&(*n)->big) && + (*n)->max_depth == (*n)->big->max_depth + 1; + } + else{ + return (*n)->max_depth == 0; + } +} + + +template +void Node::update_depth(){ + if (small && big) { + max_depth = std::max(small->max_depth, big->max_depth) + 1; + inbalance = big->max_depth - small->max_depth; + } + else if (small) { + max_depth = small->max_depth + 1; + inbalance = - small->max_depth - 1; + } + else if (big) { + max_depth = big->max_depth + 1; + inbalance = big->max_depth + 1; + } + else { + max_depth = 0; + inbalance = 0; + } +} + +template +void Node::dump(std::ofstream& ofs) const { + if (small) { + ofs << '"' << value << " : " << inbalance << '"' << " -> " << '"' << small->value << " : " << small->inbalance << '"' << '\n'; + small->dump(ofs); + } + if (big) { + ofs << '"' << value << " : " << inbalance << '"' << " -> " << '"' << big->value << " : " << big->inbalance << '"' << '\n'; + big->dump(ofs); + } +} + int main(){ Tree t; - std::vector v = {9, 2, 5, 7, 4, 8, -1, 15, 12, 17, 10, 13}; - for(auto i : v){ - if(t.insert(i)) std::cout << "added " << i << "\n"; - else std::cout << "failed at adding " << i << "\n"; - t.print(); - } - for(auto i : v){ - if(t.del(i)) std::cout << "deleted " << i << "\n"; - else std::cout << "failed at deleting " << i << "\n"; - t.print(); - } + bool test = t.test(); + if(!test) std::cout << "You're stupid!" << "\n"; + // std::vector v = {9, 2, 5, 7, 4, 8, -1, 15, 12, 17, 10, 13}; + // std::cout << "\t" << "toto je odsazene"<< "\n"; + // for(auto i : v){ + // if(t.insert(i)) std::cout << "added " << i << "\n"; + // else std::cout << "failed at adding " << i << "\n"; + // t.print(); + // } + // for(auto i : v){ + // if(t.del(i)) std::cout << "deleted " << i << "\n"; + // else std::cout << "failed at deleting " << i << "\n"; + // t.print(); + // } } \ No newline at end of file