// balance and height functions based on code from // http://www.sanfoundry.com/cpp-program-implement-avl-trees/ // Finding elements based on code from // http://www.cplusplus.com/forum/beginner/54835/ #include #include #include #include #include "json.hpp" #include "AVLCommands.h" BSTNode::BSTNode(int key) : key_(key), parent_(std::weak_ptr()), left_(nullptr), right_(nullptr), height_(0), balance_(0) {} // add a height_ BSTNode::BSTNode(int key, std::weak_ptr parent) : key_(key), parent_(parent), left_(nullptr), right_(nullptr), height_(0), balance_(0) {} bool BSTNode::IsLeaf() const { return left_ == nullptr && right_ == nullptr; } bool BSTNode::HasLeftChild() const { return left_ != nullptr; } bool BSTNode::HasRightChild() const { return right_ != nullptr; } void BSTNode::DeleteChild(std::shared_ptr v) { if (left_ == v) { left_ = nullptr; } else if (right_ == v) { right_ = nullptr; } else { std::cerr << "BSTNode::DeleteChild Error: non-child passed as argument\n"; exit(EXIT_FAILURE); } } void BSTNode::ReplaceChild(std::shared_ptr v, std::shared_ptr u) { if (left_ == u || right_ == u) { std::cerr << "BSTNode::ReplaceChild Error: child passed as replacement\n"; } if (left_ == v) { left_ = u; u->parent_ = v->parent_; } else if (right_ == v) { right_ = u; u->parent_ = v->parent_; } else { std::cerr << "BSTNode::ReplaceChild Error: non-child passed as argument\n"; exit(EXIT_FAILURE); } } AVLCommands::AVLCommands() : root_(nullptr), size_(0) {} // add height here? int AVLCommands::max(int a, int b) { return (a > b)? a : b; } int AVLCommands::height(std::shared_ptr currentNode) { //std::cout << "Updating the height..." << std::endl; //std::cout << "height: " << currentNode->height_ << std::endl; if (root_ == nullptr) { return 0; } int leftHeight, rightHeight, heightMax; if (currentNode != nullptr) { if (currentNode->left_ != nullptr) { leftHeight = height(currentNode->left_); } else { leftHeight = -1; } if (currentNode->right_ != nullptr) { rightHeight = height(currentNode->right_); } else { rightHeight = -1; } heightMax = 1 + max(leftHeight, rightHeight); currentNode->height_ = heightMax; // update balance for each node currentNode->balance_ = leftHeight - rightHeight; } return currentNode->height_; } void AVLCommands::balance(std::shared_ptr currentNode) { if (currentNode == nullptr) { return; } std::cout << "balance called at key: " << currentNode->key_ << std::endl; std::shared_ptr parent = currentNode->parent_.lock(); if (currentNode != nullptr) { //std::cout << "currentNode node key: " << currentNode->key_ << std::endl; std::cout << "balance: " << currentNode->balance_ <balance_ > 1) { if (currentNode->left_->balance_ >= 0) { std::cout << "Left-Left" << std::endl; rightRotate(currentNode); return; } else if (currentNode->left_->balance_ < 0) { std::cout << "Left-Right" << std::endl; currentNode->left_ = leftRotate(currentNode->left_); rightRotate(currentNode); return; } } else if (currentNode->balance_ < -1) { if (currentNode->right_->balance_ <= 0) { std::cout << "Right-Right" << std::endl; std::cout << "Current Node key input: " << currentNode->key_ << std::endl; leftRotate(currentNode); return; } else if (currentNode->right_->balance_ > 0) { std::cout << "Right-Left" << std::endl; currentNode->right_ = rightRotate(currentNode->right_); leftRotate(currentNode); return; } } balance(parent); } return; } std::shared_ptr AVLCommands::rightRotate(std::shared_ptr currentNode){ if (currentNode == nullptr) { std::cout << "Can't rotate on an empty node!" << std::endl; return currentNode; } std::cout << "Right Rotate at node " << currentNode->key_ << std::endl; std::shared_ptr newSubRoot = currentNode->left_; currentNode->left_ = newSubRoot->right_; if (newSubRoot->right_ != nullptr) { newSubRoot->right_->parent_ = currentNode; } newSubRoot->right_ = currentNode; std::shared_ptr oldParent = currentNode->parent_.lock(); currentNode->parent_ = newSubRoot; if (oldParent == nullptr) { root_ = newSubRoot; newSubRoot->parent_.reset(); } else { if (oldParent->right_== currentNode) { oldParent->right_ = newSubRoot; }else{ oldParent->left_ = newSubRoot; } newSubRoot->parent_ = oldParent; } // Update heights height(root_); // Return new root return newSubRoot; } // Takes the root of the tree to be left rotated and rotates it to provide new root std::shared_ptr AVLCommands::leftRotate(std::shared_ptr currentNode){ if (currentNode == nullptr) { std::cout << "Can't rotate on an empty node!" << std::endl; return currentNode; } std::cout << "Left Rotate at node " << currentNode->key_ << std::endl; std::shared_ptr newSubRoot = currentNode->right_; currentNode->right_ = newSubRoot->left_; if (newSubRoot->left_ != nullptr) { newSubRoot->left_->parent_ = currentNode; } newSubRoot->left_ = currentNode; std::shared_ptr oldParent = currentNode->parent_.lock(); currentNode->parent_ = newSubRoot; if (oldParent == nullptr) { root_ = newSubRoot; newSubRoot->parent_.reset(); } else { if (oldParent->right_== currentNode) { oldParent->right_ = newSubRoot; }else{ oldParent->left_ = newSubRoot; } newSubRoot->parent_ = oldParent; } // Update heights height(root_); // Return new root return newSubRoot; } void AVLCommands::printTree(){ printTree(root_); } void AVLCommands::printTree(std::shared_ptr currentNode){ if (root_ == nullptr) { std::cout << "tree is empty" << std::endl; return; } else { std::cout << "key: " << currentNode->key_ << std::endl; std::cout << "height: " << currentNode->height_ << std::endl; std::cout << "balance: " << currentNode->balance_ << std::endl; if (currentNode->parent_.lock() != nullptr) { std::cout << "parent: " << currentNode->parent_.lock()->key_ << std::endl; } if (currentNode->left_ != nullptr) { std::cout << "left" << std::endl; printTree(currentNode->left_); } if (currentNode->right_ != nullptr) { std::cout << "right" << std::endl; printTree(currentNode->right_); } } } void AVLCommands::Insert(int key) { std::cout << "Inserting new key: " << key << std::endl; // BST insertion if (root_ == nullptr) { root_ = std::make_shared(key); size_++; return; } std::shared_ptr currentNode = root_, lastNode = nullptr; while (currentNode != nullptr) { lastNode = currentNode; currentNode = (key < currentNode->key_) ? currentNode->left_ : currentNode->right_; } if (key < lastNode->key_) { lastNode->left_ = std::make_shared(key, lastNode); } else { lastNode->right_ = std::make_shared(key, lastNode); } size_++; // update height and balance of the tree height(root_); balance(lastNode); } bool AVLCommands::Delete(int key) { std::cout << "Deleting key: " << key << std::endl; // base BST delete std::shared_ptr currentNode = root_; std::shared_ptr parent = nullptr; while (currentNode != nullptr) { if (currentNode->key_ == key) { if (currentNode->IsLeaf()) { DeleteLeaf(currentNode); } else if (currentNode->left_ == nullptr) { assert(currentNode->right_ != nullptr); std::shared_ptr parent = currentNode->parent_.lock(); parent->ReplaceChild(currentNode, currentNode->right_); size_--; assert(size_ >= 0); } else if (currentNode->right_ == nullptr) { assert(currentNode->left_ != nullptr); std::shared_ptr parent = currentNode->parent_.lock(); parent->ReplaceChild(currentNode, currentNode->left_); size_--; assert(size_ >= 0); } else { currentNode->key_ = DeleteMin(currentNode->right_); } } parent = currentNode->parent_.lock(); currentNode = (key < currentNode->key_) ? currentNode->left_ : currentNode->right_; } height(root_); balance(parent); // Update balance factor of this ancestor's node /* // Check if unbalanced // Left Left Case if (currentNodeBalance > 1 && getBalance(currentNode->left_) >= 0) rightRotate(currentNode); // Right Right Case if (currentNodeBalance < -1 && getBalance(currentNode->right_) <= 0) leftRotate(currentNode); // Left Right Case if (currentNodeBalance > 1 && getBalance(currentNode->left_) < 0) { currentNode->left_ = leftRotate(currentNode->left_); rightRotate(currentNode); } // Right Left Case if (currentNodeBalance < -1 && getBalance(currentNode->right_) > 0) { currentNode->right_ = rightRotate(currentNode->right_); leftRotate(currentNode); } */ return false; } int AVLCommands::DeleteMin() { return DeleteMin(root_); } void AVLCommands::DeleteLeaf(std::shared_ptr currentNode) { std::shared_ptr parent = currentNode->parent_.lock(); if (parent == nullptr) { // Delete root root_ = nullptr; size_--; assert(size_ == 0); } else { if (parent->right_ == currentNode) { parent->right_ = nullptr; } else if (parent->left_ == currentNode) { parent->left_ = nullptr; } else { std::cerr << "BST::DeleteLeaf Error: inconsistent state\n"; } size_--; assert(size_ >= 0); } } int AVLCommands::DeleteMin(std::shared_ptr currentNode) { std::shared_ptr lastNode = nullptr; while (currentNode != nullptr) { lastNode = currentNode; currentNode = currentNode->left_; } int result = lastNode->key_; std::shared_ptr parent = lastNode->parent_.lock(); if (parent == nullptr) { // lastNode is root if (lastNode->right_ != nullptr) { root_ = lastNode->right_; lastNode->right_->parent_.reset(); } else { root_ = nullptr; } } else { // lastNode under the root if (lastNode->right_ != nullptr) { if (parent->left_ == lastNode){ parent->left_ = lastNode->right_; lastNode->right_->parent_ = parent; } else { parent->right_ = lastNode->right_; lastNode->right_->parent_ = parent; } } else { if (parent->left_ == lastNode){ parent->left_ = nullptr; } else { parent->right_ = nullptr; } } } size_--; assert(size_ >= 0); return result; } size_t AVLCommands::size() const { return size_; } bool AVLCommands::empty() const { return size_ == 0; } bool AVLCommands::Find(int key) const { std::shared_ptr currentNode = root_; while (currentNode != nullptr) { if (currentNode->key_ == key) { return true; } currentNode = (key < currentNode->key_) ? currentNode->left_ : currentNode->right_; } return false; } std::string AVLCommands::JSON() const { nlohmann::json result; std::queue< std::shared_ptr > nodes; if (root_ != nullptr) { result["root"] = root_->key_; nodes.push(root_); while (!nodes.empty()) { auto v = nodes.front(); nodes.pop(); std::string key = std::to_string(v->key_); //std::string height = std::to_string(v->height_); //result[key]["height"] = height; result[key]["left"] = v->left_->key_; if (v->left_ != nullptr) { result[key]["left"] = v->left_->key_; nodes.push(v->left_); } if (v->right_ != nullptr) { result[key]["right"] = v->right_->key_; nodes.push(v->right_); } if (v->parent_.lock() != nullptr) { result[key]["parent"] = v->parent_.lock()->key_; } else { result[key]["root"] = true; } } } result["size"] = size_; return result.dump(2) + "\n"; }