1. 程式人生 > >演算法導論 紅黑樹 學習 刪除(四)

演算法導論 紅黑樹 學習 刪除(四)

學習演算法 還是建議看看演算法導論

演算法導論第三版 如果不看數學推導 僅看虛擬碼 難度還是適中

本系列只是記錄我的學習心得 和虛擬碼轉化程式碼的過程

深入學習 還是建議大家看看演算法書籍 教程更加系統。

本文參考演算法導論第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;
}

執行效果圖