博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
红黑树的实现与遍历
阅读量:2394 次
发布时间:2019-05-10

本文共 9294 字,大约阅读时间需要 30 分钟。

1、红黑树的性质(参考《算法导论》):
每个节点均有颜色属性,且要么为红色,要么为黑色;
根节点为黑色;
红色节点的子节点不可以为红色
对每个节点,从该节点到期子孙节点的所有路径上包含相同数目的黑节点
2、红黑树节点的定义:
template 
class RBTNode{ private: T data; char color; RBTNode
*lchild; RBTNode
*rchild; RBTNode
*parent; private: RBTNode() : lchild(0), rchild(0), parent(0), color('R') {} RBTNode(const T& elem) : data(elem), lchild(0), rchild(0), parent(0), color('R') {} private: template
friend class RBTree; // 红黑树 template
friend class RBTreeOperator; // 另一个类,仅用于测试,可以对红黑树进行遍历};
3、红黑树类的定义:
template 
class RBTree{ public: RBTree():root(0){} ~RBTree(){} void insert(const T& elem); // 插入元素 void erase(const T& elem); // 删除元素 bool find(const T& elem); // 查找元素 void clear(); // 清除节点 private: typedef RBTNode
* pointer; private: pointer left_rotate(pointer p); // 节点左旋 pointer right_rotate(pointer p); // 节点右旋 pointer find_insert(const T& elem); // 定位待插入元素的父节点 pointer find_del(const T& elem); // 定位待删除元素 pointer find_minimum(pointer p); // 定位以p为根的子树的最小元素 pointer find_successor(pointer p); // 定位中序遍历时节点p的后继元素,同find_minimum用于定位实际删除的节点 void clear_node(pointer p); // 删除节点p private: pointer root; private: template
friend class RBTreeOperator; // 同上};
// 以下为类成员函数的实现
template
RBTNode
* RBTree
::left_rotate(RBTNode
*p) // 节点左旋,返回子树的新根节点{ if(!p || !p->rchild) { return p; } RBTNode
*q = p->rchild; p->rchild = q->lchild; if(p->rchild) { p->rchild->parent = p; } q->lchild = p; q->parent = p->parent; p->parent = q; if(!q->parent) { root = q; } else { if(p == q->parent->lchild) { q->parent->lchild = q; } else { q->parent->rchild = q; } } return q;}template
RBTNode
* RBTree
::right_rotate(RBTNode
*p){ if(!p || !p->lchild) { return p; } RBTNode
*q = p->lchild; p->lchild = q->rchild; if(p->lchild) { p->lchild->parent = p; } q->rchild = p; q->parent = p->parent; p->parent = q; if(!q->parent) { root = q; } else { if(p == q->parent->lchild) { q->parent->lchild = q; } else { q->parent->rchild = q; } } return q;}template
RBTNode
* RBTree
::find_insert(const T& elem){ RBTNode
*p(root), *q(root); while(q) { p = q; q = p->data < elem ? p->rchild : p->lchild; } return p;}template
RBTNode
* RBTree
::find_del(const T& elem){ RBTNode
*p = root; while(p) { if(p->data == elem) { break; } if(p->data < elem) { p = p->rchild; } else { p = p->lchild; } } return p;}template
RBTNode
* RBTree
::find_minimum(RBTNode
*p){ while(p && p->lchild) { p = p->lchild; } return p;}template
RBTNode
* RBTree
::find_successor(RBTNode
*p) // 查找p于中序遍历中的后继结点{ if(!p) { return p; } if(p->rchild) { return find_minimum(p->rchild); } else // 无右子节点,则向上寻找第一个为其父节点的左孩子的节点q,则q的父节点即为p的后继 { RBTNode
*q = p->parent; while(q && p == q->rchild) { p = q; q = q->parent; } return q; }}template
void RBTree
::clear_node(RBTNode
*node){ if(node) { clear_node(node->lchild); clear_node(node->rchild); delete node; }}template
void RBTree
::insert(const T& elem){ RBTNode
*p(new RBTNode
(elem)), *q(find_insert(elem)), *r(0); p->parent = q; if(!q) // 树根为空,则令新插入节点p为树根 { root = p; root->color = 'B'; return; } if(q->data < elem) { q->rchild = p; } else { q->lchild = p; } while(q && q != root && q->color == 'R') //p与其父节点q的颜色均为红色,违反定义 { RBTNode
*node = q->parent; if(q == node->lchild) // 若q为其父节点的左孩子 { r = node->rchild; // r为p的叔父 if(r && r->color == 'R') // 若q与r的颜色均为红,则将二者颜色变黑,其父节点变红,并将p指向该父节点,下一步循环 { r->color = 'B'; q->color = 'B'; node->color = 'R'; p = node; q = p->parent;
				continue;
						}
			if(p == q->rchild) // 若p为q的右孩子,则应将q左旋并交换地址,使得p为q的左孩子			{				left_rotate(q);				p = q;				q = p->parent;			}			right_rotate(node); // 通过将node节点右旋以及node与q的颜色交换,使该子树根节点为黑色,同时消除了红-红父子冲突			q->color = 'B';			node->color = 'R';		}		else		{			r = node->lchild;			if(r && r->color == 'R')			{				r->color = 'B';				q->color = 'B';				node->color = 'R';				p = node;				q = p->parent;
				continue;			}			else			{				if(p == q->lchild)				{					right_rotate(q);					p = q;					q = p->parent;				}				left_rotate(node);				q->color = 'B';				node->color = 'R';			}		}	}	root->color = 'B'; // 根节点染红}template 
void RBTree
::erase(const T& elem){ RBTNode
*q(find_del(elem)), *p(0), *r(0), *node(0); if(!q) { return; } if(!q->lchild || !q->rchild) // q孩子数少于2,则直接删除q即可 { node = q; } else // 否则删除其后继位置的节点node,node必然不会同时有左右两个孩子 { node = find_successor(q); } if(node != q) // 将node的值赋值到q { q->data = node->data; }
	// 以下代码处理被删除节点为根节点或者无子节点的情况	q = node->parent;	p = (node->lchild ? node->lchild : node->rchild);	if(q)	{		if(node == q->lchild)		{			q->lchild = p;		}		else		{			q->rchild = p;		}	}	else	{		root = p;	}	if(!p)	{		delete node;		return;	}	else	{		p->parent = q;	}		if(node->color == 'B') // 若被删除节点为黑色,则其所在的路径上少了一个黑色节点,需要矫正	{		while(p != root && p->color == 'B') // 循环条件:还未遇到红色节点以染成黑色		{			q = p->parent;			if(p == q->lchild) // 若p为其父节点q的左孩子			{				r = q->rchild; // r为q的右孩子,p的兄弟节点				if(!r) // q只有一个孩子,无需处理该子树,p上移一层				{					p = q;					continue;				}				if(r->color == 'R') // 若r为红色,则通过q的左旋以及r与q的颜色交换,转换为p的兄弟为黑色的情况(后边处理该情况)				{					r->color = 'B';					q->color = 'R';					left_rotate(q);					r = q->rchild;

}

// 以下为p的兄弟节点r为黑色的情况,分三种情况处理:

				if((!r->lchild ||r->lchild->color == 'B') && (!r->rchild || r->rchild->color == 'B')) // 1)r的子节点均不为红色,则将r染成				红色,使得q向下缺少一层黑色,故可将p指向q,上移 				{					r->color = 'R';					p = q;				}				else				{					if(!r->rchild || r->rchild->color == 'B') // 2)r的右子节点为空或黑色,通过旋转使p的兄弟右孩子为红色					{						r->color = 'R';						r->lchild->color = 'B';						r = right_rotate(r);					}					r->color = q->color; // 3)r的右子节点为红色,将q左旋并通过颜色交换,使得右子树的一个黑色为左右共享,左子树不再缺少					黑色,结束循环即可					q->color = 'B';					r->rchild->color = 'B';					left_rotate(q);					p = root;				}			}			else // if代码的镜像			{				r = q->lchild;				if(!r)				{					p = q;					continue;				}				if(r->color == 'R')				{					r->color = 'B';					q->color = 'R';					right_rotate(q);					r = q->lchild;				}				if((!r->lchild || r->lchild->color == 'B') && (!r->rchild || r->rchild->color == 'B'))				{					r->color = 'R';					p = q;				}				else				{					if(!r->lchild || r->lchild->color == 'B')					{						r->color = 'R';						r->rchild->color = 'B';						r = left_rotate(r);					}					r->color = q->color;					q->color = 'B';					r->lchild->color = 'B';					right_rotate(q);					p = root;				}			}		}		p->color = 'B'; // 找到了可以弥补的节点,将其染成黑色	}	delete node; //删除node即可}template 
bool RBTree
::find(const T& elem){ return find_del(elem) != 0;}template
void RBTree
::clear(){ clear_node(root); root = 0;}
4、 树的遍历:
 
template 
class RBTreeOperator{ public: RBTreeOperator() : tree(0) {} RBTreeOperator(RBTree
& t) : tree(&t){} ~RBTreeOperator(){} void FirstOrderTree(); void InOrderTree(); void PostOrderTree(); void LevelOrderTree(); private: void FTraverse(RBTNode
*node); void ITraverse(RBTNode
*node); void PTraverse(RBTNode
*node); void LTraverse(RBTNode
*node); private: RBTree
*tree;};
// 以下为成员函数的实现
template 
void RBTreeOperator
::FTraverse(RBTNode
*node){ stack
*> s; s.push(node); if(!node) { return; } while(!s.empty()) { node = s.top(); s.pop(); cout << node->data << "\t"; if(node->rchild) { s.push(node->rchild); } if(node->lchild) { s.push(node->lchild); } }}template
void RBTreeOperator
::ITraverse(RBTNode
*node){ stack
*> s; while(node) { s.push(node); node = node->lchild; } while(!s.empty()) { node = s.top(); cout << node->data << "\t"; s.pop(); RBTNode
*temp = node->rchild; while(temp) { s.push(temp); temp = temp->lchild; } }}template
void RBTreeOperator
::PTraverse(RBTNode
*node){ stack
*> s; RBTNode
*p(node), *q(0); while(p) { s.push(p); p = p->lchild; } while(!s.empty()) { p = s.top(); if(p->rchild && q != p->rchild) { p = p->rchild; while(p) { s.push(p); p = p->lchild; } } else { q = p; cout << p->data << "\t"; s.pop(); } }}template
void RBTreeOperator
::LTraverse(RBTNode
*node){ queue
*> q; if(!node) { return; } q.push(node); while(!q.empty()) { node = q.front(); if(node->lchild) { q.push(node->lchild); } if(node->rchild) { q.push(node->rchild); } cout << node->data << "\t"; q.pop(); }}template
void RBTreeOperator
::FirstOrderTree(){ FTraverse(tree->root); cout << endl;}template
void RBTreeOperator
::InOrderTree(){ ITraverse(tree->root); cout << endl;}template
void RBTreeOperator
::PostOrderTree(){ PTraverse(tree->root); cout << endl;}template
void RBTreeOperator
::LevelOrderTree(){ LTraverse(tree->root); cout << endl;}
5、测试:
 
int main(int argc, char** argv) {	RBTree
tree; RBTreeOperator
op(tree); const int N(10); int p[N] = {2, 5, 3, 9, 7, 8, 6, 10, 1, 4}; for(int i = 0; i < N; ++i) { tree.insert(p[i]); } op.FirstOrderTree(); op.InOrderTree(); op.PostOrderTree(); op.LevelOrderTree(); for(int i = 0; i < N; ++i) { tree.erase(p[i]); op.FirstOrderTree(); op.InOrderTree(); } return 0;}
6、小结:
 
以上便是今天下午的劳动成果了。写完代码后感觉对红黑树的理解更深入一些了,更重要的是对节点旋转的作用以及需要节点旋转的场合有了更深的了解:通过旋转可以使一个节点的左右两颗子树“互通有无”,弥补其中一棵子树缺少的颜色,这是通过对另一棵子树的某个节点的颜色进行共享实现的。另一收获就是码代码的时候万万要小心,一个不细心导致的错误,将会让你付出很大的代价去发现它!
 
 

转载地址:http://jyzob.baihongyu.com/

你可能感兴趣的文章
正好碰到了C++的函数对象,查各路资料,总结写下来吧
查看>>
今天试vi遇到的“Sorry,the command is not available in this version : syntax on”
查看>>
今天又搞到个libDTL.so is not an ELF file - it has the wrong magic bytes at the start.
查看>>
MinGW和vc6中编译DTL的过程
查看>>
Fedora13下为postgresql添加ODBC驱动过程
查看>>
Bridge模式学习
查看>>
Virtual的一些总结
查看>>
Fedora13上折腾了下ACE
查看>>
tomcat keepAliveTimeout=0问题
查看>>
JDK1.6在SUSE11下问题跳变定时任务失效问题记录
查看>>
400 Bad request 一例
查看>>
linux文件锁定
查看>>
fedora4上安装gcc2.9,编译安装rainbow过程
查看>>
求质数算法的N种境界 (N > 10)
查看>>
一个简单的linux下原生socket的tcp程序及其修改
查看>>
JSP的入门简介
查看>>
JSP中的基本语法和3指令,6动作,9内置对象
查看>>
JSP的6个动作
查看>>
JAVA中的数据类型和方法重载
查看>>
常见面试题——斐波纳挈数列
查看>>