演算法導論 紅黑樹 學習 刪除(四)
阿新 • • 發佈:2019-02-12
學習演算法 還是建議看看演算法導論
演算法導論第三版 如果不看數學推導 僅看虛擬碼 難度還是適中
本系列只是記錄我的學習心得 和虛擬碼轉化程式碼的過程
深入學習 還是建議大家看看演算法書籍 教程更加系統。
本文參考演算法導論第13章節 紅黑樹
程式碼由本人寫成
轉載請標明出處
先看看不做顏色處理的刪除
不做顏色處理的刪除基本就和二叉樹類似
如果刪除節點沒有子樹 最簡單 直接刪除
如果待刪除的節點只有一個兒子(左子樹或者右子樹) 那麼刪除該節點 兒子補上即可
void RBTransplant(std::shared_ptr<node>& root, std::shared_ptr<node> u, std::shared_ptr<node> v) { if (u->parent_ == nil) root = v; else if (u == u->parent_->left_) u->parent_->left_ = v; else u->parent_->right_ = v; v->parent_ = u->parent_; }
u是要刪除的節點 v是補上的節點
過程如圖:
若是待刪除節點有兩個子樹 那麼尋找待刪除節點右子樹最小的節點,這個節點要麼就是刪除節點右子樹,要麼就是沿著刪除節點右子樹向左遍歷的終點
如圖: 如果7是待刪除節點,那麼目標不是11 就是9
將刪除節點和目標節點值互換 在處理目標節點 那麼就把兩棵子樹節點的刪除更改為無子樹或者單子樹節點的刪除,很巧妙!
虛擬碼如圖
刪除程式碼及測試程式碼如下(刪除未調整顏色版本,可執行)
// rbTreeTest.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <memory> #include <iostream> using namespace std; enum Color { red = 1, black }; struct node { Color color_; std::shared_ptr<node> left_; std::shared_ptr<node> right_; std::shared_ptr<node> parent_; int value_; node() { left_ = right_ = parent_ = nullptr; value_ = -1; color_ = black; } }; std::shared_ptr<node> nil(new node); std::shared_ptr<node> CreateNode(Color color, int i) { std::shared_ptr<node> p(new node); p->color_ = color; p->left_ = nil; p->right_ = nil; p->parent_ = nil; p->value_ = i; return p; } void RightRotate(std::shared_ptr<node>& root, std::shared_ptr<node> x) { std::shared_ptr<node> y = x->left_; x->left_ = y->right_; if (y->right_ != nil) y->right_->parent_ = x; y->parent_ = x->parent_; if (x->parent_ == nil) { root = y; } else if (x->parent_->left_ == x) { x->parent_->left_ = y; } else { x->parent_->right_ = y; } y->right_ = x; x->parent_ = y; } void LeftRotate(std::shared_ptr<node>& root, std::shared_ptr<node> x) { std::shared_ptr<node> y = x->right_; x->right_ = y->left_; if (y->left_ != nil) y->left_->parent_ = x; y->parent_ = x->parent_; if (x->parent_ == nil) { root = y; } else if (x->parent_->left_ == x) { x->parent_->left_ = y; } else { x->parent_->right_ = y; } y->left_ = x; x->parent_ = y; } void PrinTree(std::shared_ptr<node> root) { if (root == nil) { std::cout << "nil:" << ":color-" << root->color_ << " ; " << std::endl << std::endl; return; } std::cout << root->value_ << ":color-" << root->color_ << "; address:" << root << std::endl; if (root->parent_ == nil) { std::cout << "parent_:" << "nil" << std::endl; } else { std::cout << "parent_:" << root->parent_->value_ << std::endl; } if (root->left_ == nil) { std::cout << "left_:" << "nil" << std::endl; } else { std::cout << "left_:" << root->left_->value_ << std::endl; } if (root->right_ == nil) { std::cout << "right_:" << "nil" << std::endl; } else { std::cout << "right_:" << root->right_->value_ << std::endl; } std::cout << std::endl; if (root->left_ != nil) PrinTree(root->left_); if (root->right_ != nil) PrinTree(root->right_); } void RBInsertFixup(std::shared_ptr<node>& root, std::shared_ptr<node> z) { while (z->parent_->color_ == red) { //插入節點Z是紅色 若Z父節點也是紅色則需要調整 if (z->parent_ == z->parent_->parent_->left_) { // 父節點是左子樹的情況 std::shared_ptr<node> y = z->parent_->parent_->right_; if (y->color_ == red) { // 情況1 z->parent_->color_ = black; y->color_ = black; z->parent_->parent_->color_ = red; z = z->parent_->parent_; } else { if (z == z->parent_->right_) { z = z->parent_; // 情況2 LeftRotate(root, z); } z->parent_->color_ = black; // 情況3 z->parent_->parent_->color_ = red; RightRotate(root, z->parent_->parent_); } } else {// 父節點是右子樹的情況 與上面判斷處理均是映象對稱 std::shared_ptr<node> y = z->parent_->parent_->left_; if (y->color_ == red) { z->parent_->color_ = black; y->color_ = black; z->parent_->parent_->color_ = red; z = z->parent_->parent_; } else { if (z == z->parent_->left_) { z = z->parent_; RightRotate(root, z); } z->parent_->color_ = black; z->parent_->parent_->color_ = red; LeftRotate(root, z->parent_->parent_); } } }//while (z->parent_->color_ == red) root->color_ = black; }//function end void RBInsert(std::shared_ptr<node>& root, std::shared_ptr<node> ins) { std::shared_ptr<node> y = nil; std::shared_ptr<node> x = root; while (x != nil) { y = x; if (ins->value_ < x->value_) { x = x->left_; } else { x = x->right_; } } ins->parent_ = y; if (y == nil) { root = ins; } else if (ins->value_ < y->value_) { y->left_ = ins; } else { y->right_ = ins; } ins->left_ = ins->right_ = nil; ins->color_ = red; // todo fixup RBInsertFixup(root, ins); } std::shared_ptr<node> CreateRB() { std::shared_ptr<node> root = nil; std::shared_ptr<node> x = CreateNode(red, 7); RBInsert(root, x); x = CreateNode(red, 4); RBInsert(root, x); x = CreateNode(red, 11); RBInsert(root, x); x = CreateNode(red, 3); RBInsert(root, x); //PrinTree(root); //std::cout << std::endl; return root; } //============================================= // delete test std::shared_ptr<node> RBMinimum(std::shared_ptr<node> n) { while (n->left_ != nil) { n = n->left_; } return n; } std::shared_ptr<node> RBMaximum(std::shared_ptr<node> n) { while (n->right_ != nil) { n = n->right_; } return n; } std::shared_ptr<node> RBSuccessor(std::shared_ptr<node> n) { if (n->right_ != nil) return RBMinimum(n->right_); std::shared_ptr<node> y = n->parent_; while (y != nil && n == y->right_) { n = y; y = y->parent_; } return y; } void RBTransplant(std::shared_ptr<node>& root, std::shared_ptr<node> u, std::shared_ptr<node> v) { if (u->parent_ == nil) root = v; else if (u == u->parent_->left_) u->parent_->left_ = v; else u->parent_->right_ = v; v->parent_ = u->parent_; } void RBDelete(std::shared_ptr<node>& root,std::shared_ptr<node> z) { if (root == nil || z == nil) { return; } std::shared_ptr<node> y = z; Color original_color = y->color_; std::shared_ptr<node> x; if (z->left_ == nil) { x = z->right_; RBTransplant(root, z, z->right_); } else if (z->right_ == nil) { x = z->left_; RBTransplant(root, z, z->left_); } else { y = RBMinimum(z->right_); original_color = y->color_; x = y->right_; if (y->parent_ == z) x->parent_ = y; else { RBTransplant(root,y,y->right_); y->right_ = z->right_; y->right_->parent_ = y; } RBTransplant(root,z,y); y->left_ = z->left_; y->left_->parent_ = y; y->color_ = z->color_; } if (y->color_ == black) {} //RBDeleteFixup(root,x); } //============================================= int main() { std::shared_ptr<node> root = CreateRB(); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root,root); PrinTree(root); std::cout << std::endl; RBDelete(root, root); PrinTree(root); std::cout << std::endl; RBDelete(root, root); PrinTree(root); std::cout << std::endl; RBDelete(root, root); PrinTree(root); std::cout << std::endl; RBDelete(root, root); PrinTree(root); std::cout << std::endl; return 0; }
最後全部程式碼如下 增刪 列印 調整功能 可執行除錯
// rbTreeTest.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <memory> #include <iostream> using namespace std; enum Color { red = 1, black }; struct node { Color color_; std::shared_ptr<node> left_; std::shared_ptr<node> right_; std::shared_ptr<node> parent_; int value_; node() { left_ = right_ = parent_ = nullptr; value_ = -1; color_ = black; } }; std::shared_ptr<node> nil(new node); std::shared_ptr<node> CreateNode(Color color, int i) { std::shared_ptr<node> p(new node); p->color_ = color; p->left_ = nil; p->right_ = nil; p->parent_ = nil; p->value_ = i; return p; } void RightRotate(std::shared_ptr<node>& root, std::shared_ptr<node> x) { std::shared_ptr<node> y = x->left_; x->left_ = y->right_; if (y->right_ != nil) y->right_->parent_ = x; y->parent_ = x->parent_; if (x->parent_ == nil) { root = y; } else if (x->parent_->left_ == x) { x->parent_->left_ = y; } else { x->parent_->right_ = y; } y->right_ = x; x->parent_ = y; } void LeftRotate(std::shared_ptr<node>& root, std::shared_ptr<node> x) { std::shared_ptr<node> y = x->right_; x->right_ = y->left_; if (y->left_ != nil) y->left_->parent_ = x; y->parent_ = x->parent_; if (x->parent_ == nil) { root = y; } else if (x->parent_->left_ == x) { x->parent_->left_ = y; } else { x->parent_->right_ = y; } y->left_ = x; x->parent_ = y; } void PrinTree(std::shared_ptr<node> root) { if (root == nil) { std::cout << "nil:" << ":color-" << root->color_ << " ; " << std::endl << std::endl; return; } std::cout << root->value_ << ":color-" << root->color_ << "; address:" << root << std::endl; if (root->parent_ == nil) { std::cout << "parent_:" << "nil" << std::endl; } else { std::cout << "parent_:" << root->parent_->value_ << std::endl; } if (root->left_ == nil) { std::cout << "left_:" << "nil" << std::endl; } else { std::cout << "left_:" << root->left_->value_ << std::endl; } if (root->right_ == nil) { std::cout << "right_:" << "nil" << std::endl; } else { std::cout << "right_:" << root->right_->value_ << std::endl; } std::cout << std::endl; if (root->left_ != nil) PrinTree(root->left_); if (root->right_ != nil) PrinTree(root->right_); } void RBInsertFixup(std::shared_ptr<node>& root, std::shared_ptr<node> z) { while (z->parent_->color_ == red) { //插入節點Z是紅色 若Z父節點也是紅色則需要調整 if (z->parent_ == z->parent_->parent_->left_) { // 父節點是左子樹的情況 std::shared_ptr<node> y = z->parent_->parent_->right_; if (y->color_ == red) { // 情況1 z->parent_->color_ = black; y->color_ = black; z->parent_->parent_->color_ = red; z = z->parent_->parent_; } else { if (z == z->parent_->right_) { z = z->parent_; // 情況2 LeftRotate(root, z); } z->parent_->color_ = black; // 情況3 z->parent_->parent_->color_ = red; RightRotate(root, z->parent_->parent_); } } else {// 父節點是右子樹的情況 與上面判斷處理均是映象對稱 std::shared_ptr<node> y = z->parent_->parent_->left_; if (y->color_ == red) { z->parent_->color_ = black; y->color_ = black; z->parent_->parent_->color_ = red; z = z->parent_->parent_; } else { if (z == z->parent_->left_) { z = z->parent_; RightRotate(root, z); } z->parent_->color_ = black; z->parent_->parent_->color_ = red; LeftRotate(root, z->parent_->parent_); } } }//while (z->parent_->color_ == red) root->color_ = black; }//function end void RBInsert(std::shared_ptr<node>& root, std::shared_ptr<node> ins) { std::shared_ptr<node> y = nil; std::shared_ptr<node> x = root; while (x != nil) { y = x; if (ins->value_ < x->value_) { x = x->left_; } else { x = x->right_; } } ins->parent_ = y; if (y == nil) { root = ins; } else if (ins->value_ < y->value_) { y->left_ = ins; } else { y->right_ = ins; } ins->left_ = ins->right_ = nil; ins->color_ = red; // todo fixup RBInsertFixup(root, ins); } std::shared_ptr<node> CreateRB() { std::shared_ptr<node> root = nil; std::shared_ptr<node> x = CreateNode(red, 15); RBInsert(root, x); x = CreateNode(red, 10); RBInsert(root, x); x = CreateNode(red, 20); RBInsert(root, x); x = CreateNode(red, 5); RBInsert(root, x); x = CreateNode(red, 13); RBInsert(root, x); x = CreateNode(red, 17); RBInsert(root, x); x = CreateNode(red, 25); RBInsert(root, x); return root; } //============================================= // delete test std::shared_ptr<node> RBMinimum(std::shared_ptr<node> n) { while (n->left_ != nil) { n = n->left_; } return n; } std::shared_ptr<node> RBMaximum(std::shared_ptr<node> n) { while (n->right_ != nil) { n = n->right_; } return n; } std::shared_ptr<node> RBSuccessor(std::shared_ptr<node> n) { if (n->right_ != nil) return RBMinimum(n->right_); std::shared_ptr<node> y = n->parent_; while (y != nil && n == y->right_) { n = y; y = y->parent_; } return y; } void RBTransplant(std::shared_ptr<node>& root, std::shared_ptr<node> u, std::shared_ptr<node> v) { if (u->parent_ == nil) root = v; else if (u == u->parent_->left_) u->parent_->left_ = v; else u->parent_->right_ = v; v->parent_ = u->parent_; } void RBDeleteFixup(std::shared_ptr<node>& root, std::shared_ptr<node> x) { while (x != root && x->color_ == black) { if (x == x->parent_->left_) { std::shared_ptr<node> w = x->parent_->right_; if (w->color_ == red) { w->color_ = black; x->parent_->color_ = red; LeftRotate(root, x->parent_); w = x->parent_->right_; } if (w->left_->color_ == black && w->right_->color_ == black) { w->color_ = red; x = x->parent_; } else { if (w->right_->color_ == black) { w->left_->color_ = black; w->color_ = red; RightRotate(root,w); w = x->parent_->right_; } w->color_ = x->parent_->color_; x->parent_->color_ = black; w->right_->color_ = black; LeftRotate(root,x->parent_); x = root; } }else { std::shared_ptr<node> w = x->parent_->left_; if (w->color_ == red) { w->color_ = black; x->parent_->color_ = red; RightRotate(root, x->parent_); w = x->parent_->left_; } if (w->right_->color_ == black && w->left_->color_ == black) { w->color_ = red; x = x->parent_; } else { if (w->left_->color_ == black) { w->right_->color_ = black; w->color_ = red; LeftRotate(root, w); w = x->parent_->left_; } w->color_ = x->parent_->color_; x->parent_->color_ = black; w->left_->color_ = black; RightRotate(root, x->parent_); x = root; } } }//while (x != root && x->color_ == black) x->color_ = black; } void RBDelete(std::shared_ptr<node>& root,std::shared_ptr<node> z) { if (root == nil || z == nil) return; std::shared_ptr<node> y; std::shared_ptr<node> x; if (z->left_ == nil || z->right_ == nil) { y = z; } else { y = RBSuccessor(z); } if (y->left_ != nil) { x = y->left_; } else { x = y->right_; } x->parent_ = y->parent_; if (y->parent_ == nil) { root = x; } else { if (y == y->parent_->left_) { y->parent_->left_ = x; } else { y->parent_->right_ = x; } } if (y != z) { z->value_ = y->value_; } if (y->color_ == black) { //todo RBDeleteFixup(root,x); } } //============================================= int main() { std::shared_ptr<node> root = CreateRB(); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root,root); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root, root); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root, root); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root, root); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root, root); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root, root); PrinTree(root); std::cout << "===========================" << std::endl; RBDelete(root, root); PrinTree(root); std::cout << "===========================" << std::endl; return 0; }
執行效果圖