算法导论学习-红黑树

红黑树特殊性质:

1.每个结点或是红色的,或是黑色的;
2.根结点是黑色的;
3.每个叶节点是黑色的;
4.若一个是红色的,则他的两个子节点都是黑色的;
5.对每个结点,从该结点到其所有后代叶节点的简单路径上,黑色结点数相同

这里的叶节点指的是空结点,参考算法导论,设置一个尾指针Nail代表叶节点,空的左右孩子一律连接在Nail上)

高度:

一.类:

enum color { RED, BLACK };
struct Node
{
	int key;
	color co;
	Node* left;
	Node* right;
	Node* p;
	Node(int k, Node* a, Node* b, color c) :key(k), co(c), left(a), right(b), p(nullptr) {}
};
class Tree
{
private:
	Node * root;
	void Left(Node* x);
	void Right(Node* x);
	void Transplant(Node* u, Node* v);
	void preOrder(Node*);
	void inOrder(Node*);
	void postOrder(Node*);
	int height(Node*);
	Node* Max();
	Node* Min();
public:
	Node * Root() { return root; }
	Node* Nail;
	Tree();
	bool Insert(int k);
	void bfs(Node*);
	void Delete(Node* z);
	Node* Min(Node* x);
	Node* Search(int k);
	void PreOrder();
	void InOrder();
	void PostOrder();
	Node* max(Node*);
	Node* min(Node*);
	int Height();
};

二.旋转操作:左旋和右旋

void Tree::Left(Node* x)
{
	Node* s = x->right;
	x->right = s->left;
	if (s->left != Nail)//防止对尾指针操作
		s->left->p = x;
	s->p = x->p;
	if (x->p == Nail)//更新根结点
	{
		root = s;
	}
	else if (x == x->p->left)
		x->p->left = s;
	else x->p->right = s;
	s->left = x;
	x->p = s;
}
void Tree::Right(Node* x)
{
	Node* s = x->left;
	x->left = s->right;
	if (s->right != Nail)
		s->right->p = x;
	s->p = x->p;
	if (x->p == Nail)
		root = s;
	else if (x == x->p->left)
		x->p->left = s;
	else x->p->right = s;
	s->right = x;
	x->p = s;
}

三.插入操作:

插入z时,将z先作为红色。此时,性质1,3,5均不会被破坏。若z是根结点,则性质2被破坏;若z的父节点为红色,则性质4被破坏。

实现中使用迭代更新z,while中保持如下循环不变式:

1. z为红色结点
2. 若z.p为根结点,则z.p为黑色结点
3. 性质至多只有一条没破坏,或者为2、或者为4.

Case1:    z的叔结点y为红色。z.p.p(原来必为黑)变成红色;z.p和y着为黑色。z.p.p成为新的z结点重复while循环。  

扫描二维码关注公众号,回复: 1048842 查看本文章
            这时,以z.p.p为根的子树中红黑树性质不变,且各路径上黑色结点数目不变,性质5不可能被破坏。


Case2: y为黑色且z为一个右结点
Case3: y为黑色且z为一个左结点

此时z.p为黑色,不必再重复while循环。

bool Tree::Insert(int k)
{
	Node* z = new Node(k, Nail, Nail, RED);//先设置为红色
	Node* x = root;
	Node* y = Nail;
	while (x != Nail)//寻找插入位置
	{
		y = x;
		if (z->key < x->key)
			x = x->left;
		else if (z->key > x->key)
			x = x->right;
		else
		{
			cout << "Two equal is banned!\n";
			return false;
		}
	}
	//x指向尾节点,y为该路径上最后一个非空结点
	z->p = y;
	if (y == Nail)//空树
		root = z;
	else if (z->key < y->key)
		y->left = z;
	else y->right = z;
	while (z != root && z->p->co == RED)//开始循环
	{
		if (z->p == z->p->p->left)//确定叔结点是左孩子还是右孩子
		{
			y = z->p->p->right;//y是z的叔结点
			if (y->co == RED)//                                Case1
			{
				z->p->co = BLACK;
				z->p->p->co = RED;
				y->co = BLACK;
				z = z->p->p;
			}
			else
			{
				if (z == z->p->right)                   //Case2 转化为 Case3
				{
					z = z->p;//更新z
					Left(z);
				}
				z->p->co = BLACK;
				z->p->p->co = RED;
				Right(z->p->p);
			}
		}
		else//同上
		{
			y = z->p->p->left;
			if (y->co == RED)
			{
				z->p->co = BLACK;
				z->p->p->co = RED;
				y->co = BLACK;
				z = z->p->p;
			}
			else
			{
				if (z == z->p->left)
				{
					z = z->p;
					Right(z);
				}
				z->p->co = BLACK;
				z->p->p->co = RED;
				Left(z->p->p);
			}
		}
	}
	root->co = BLACK;
	return true;
}


四.删除:

首先一个子过程,用于替换结点

void Tree::Transplant(Node* u, Node* v)//以v替换u
{
	if (u->p == Nail)
		root = v;
	else if (u == u->p->left)
		u->p->left = v;
	else
		u->p->right = v;
	if (v != Nail)
		v->p = u->p;
}

令z为要删除的结点,y为实际删除或移动的结点,x为y的孩子。
当z有两个孩子,y为z的后继,并将y移动至z的位置,同时必须记录y原来的颜色,y的实际颜色变为z的颜色。x移动到y原来的位置。

此时,若y原来为红色,则红黑树性质仍保持,原因如下:
1.树的黑高没有变化;
2.不存在两个相邻的红节点(x一定为黑色);
3.y是红色,则y不可能是根结点,根结点仍为黑色。

若y为黑色会产生三个问题:
1.若y为根结点,同时y的一个红孩子成了根结点,违反性质2;
2.若x和x.p为红色,违反性质5;
3.在树中移动y会导致原先包含y的简单路径上黑结点数少一。

现维护红黑树性质,分四种情况:
(若x为红色,直接着色为黑色即可)(x为黑色是迭代,以下维持性质4)
(x可理解为包含了所有黑色结点均少一的简单路径的子树)
Case1:  x的兄弟结点w为红色。通过一次左旋转换为情况二,同时w和x.p的颜色互换。
Case2:  x的兄弟结点w为黑色,w的两个子节点都是黑色。w着色为红色,x上移为x.p。(拉兄弟下水)
           若是由Case1转向的Case2,则在循环测试时可终止。(新的x为红色)(情况一下,w为红色,则x.p必为黑色,互换后               变为红色)。
Case3:  x的兄弟结点w为黑色,w左孩子红,w右孩子黑。右旋,并交换w和w.left的颜色,x不变,更新w。转到Case。
Case4:  x的兄弟节点w为黑色,w右孩子为红色。对x.p一次左旋。w.right着色为黑色,w着色为x.p的颜色,x.p不论红黑均着                  色为黑色。此时x包含的简单路径黑色结点数加一,其余不变,性质得到维持,x设为根,可以跳出循环。

(寻求使x的父节点变成红色再被设置为黑色)
void Tree::Delete(Node* z)
{
	color Ori = z->co;//y原先的颜色
	Node* x;//实际消失结点的孩子
	Node* y = z;//y实际消失的结点
	if (z->left == Nail)
	{
		x = z->right;
		Transplant(z, z->right);
	}
	else if (z->right == Nail)
	{
		x = z->left;
		Transplant(z, z->left);
	}
	else//左右皆非空,y应为z的后继
	{
		y = Min(z->right);
		Ori = y->co;//y发生改变,更新y原来的颜色
		x = y->right;
		if (y->p != z)
		{
			Transplant(y, y->right);
			y->right = z->right;
			y->right->p = y;
		}
		Transplant(z, y);
		y->left = z->left;
		y->left->p = y;
		y->co = z->co;
	}
	if (Ori == BLACK)//维持性质
	{
		Node* w;
		if (x == Nail)//便于对叶节点操作
			x->p = y;
		while (x != root && x->co == BLACK)
		{
			if (x == x->p->left)
			{
				w = x->p->right;
				if (w->co == RED)
				{
					w->co = BLACK;
					x->p->co = RED;
					Left(x->p);
					w = x->p->right;
				}
				if (w->left->co == BLACK && w->right->co == BLACK)
				{
					w->co = RED;
					x = x->p;
				}
				else
				{
					if (w->right->co == BLACK)
					{
						w->left->co = BLACK;
						w->co = RED;
						Right(w);
						w = x->p->right;
					}
					w->co = x->p->co;
					x->p->co = BLACK;
					w->right->co = BLACK;
					Left(x->p);
					x = root;
				}
			}
			else//与上面对称
			{
				w = x->p->left;
				if (w->co == RED)
				{
					w->co = BLACK;
					x->p->co = RED;
					Right(x->p);
					w = x->p->left;
				}
				if (w->right->co == BLACK && w->left->co == BLACK)
				{
					w->co = RED;
					x = x->p;
				}
				else
				{
					if (w->left->co == BLACK)
					{
						w->right->co = BLACK;
						w->co = RED;
						Left(w);
						w = x->p->left;
					}
					w->co = x->p->co;
					x->p->co = BLACK;
					w->left->co = BLACK;
					Right(x->p);
					x = root;
				}
			}
		}
		x->co = BLACK;
	}
}


其它功能:

Node* Tree::Search(int x)
{
	Node* t = root;
	while (t != Nail && t->key != x)
	{
		if (x < t->key)
			t = t->left;
		else t = t->right;
	}
	return t;
}
Node* Tree::Min(Node* x)    //以x为根子树最小元素
{
	while (x->left != Nail)
		x = x->left;
	return x;
}
void Tree::bfs(Node* x)
{
	if (x == Nail)
		return;
	queue<Node*> q;
	q.push(x);
	Node* t;
	while (!q.empty())
	{
		t = q.front();
		q.pop();
		if (t->left != Nail)
		{
			if (t->co == RED)
				cout << "RED ";
			else
				cout << "BLACK ";
			cout << t->key << "'s L : ";
			if (t->left->co == RED)
				cout << "RED ";
			else
				cout << "BLACK ";
			cout << t->left->key << '\t' << endl;
			q.push(t->left);
		}
		if (t->right != Nail)
		{
			if (t->co == RED)
				cout << "RED ";
			else
				cout << "BLACK ";
			cout << t->key << "'s R : ";
			if (t->right->co == RED)
				cout << "RED ";
			else
				cout << "BLACK ";
			cout << t->right->key << endl;
			q.push(t->right);
		}
	}
}
void Tree::preOrder(Node* a)
{
	if (a != nullptr)
	{
		cout << a->key;
		preOrder(a->left);
		preOrder(a->right);
	}
}
void Tree::PreOrder()
{
	preOrder(root);
}

void Tree::inOrder(Node* a)
{
	if (a != nullptr)
	{
		inOrder(a->left);
		cout << a->key;
		inOrder(a->right);
	}
}
void Tree::InOrder()
{
	inOrder(root);
}

void Tree::postOrder(Node* a)
{
	if (a != nullptr)
	{
		postOrder(a->left);
		postOrder(a->right);
		cout << a->key;
	}
}
void Tree::PostOrder()
{
	postOrder(root);
}

Node* Tree::max(Node* t)
{
	if (t == nullptr || t == Nail)
		return nullptr;
	else
	{
		while (t->right != Nail)
			t = t->right;
		return t;
	}
}
Node* Tree::Max()
{
	return max(root);
}

Node* Tree::min(Node* t)
{
	if (t == Nail || t == nullptr)
		return nullptr;
	else
	{
		while (t->left != Nail)
			t = t->left;
		return t;
	}
}
Node* Tree::Min()
{
	return min(root);
}

int Tree::height(Node* t)
{
	int h1 = 0, h2 = 0;
	if (t != Nail)
	{
		h1 = height(t->left) + 1;
		h2 = height(t->right) + 1;
		return h1 > h2 ? h1 : h2;
	}
	else
		return 0;
}

int Tree::Height()
{
	return height(root);
}


猜你喜欢

转载自blog.csdn.net/qq_40510553/article/details/80225136
今日推荐