红黑树插入

来源:互联网 发布:天地知我心儿的小说 编辑:程序博客网 时间:2024/06/02 06:03

一、什么是红黑树

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。

它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”(百度百科)


红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是RED或BLACK。

一棵红黑树是满足下面红黑性质的二叉搜索树:

1、每一个结点或是红结点或是黑结点

2、根节点是黑色的

3、每个叶节点(NIL)是黑色的

4、如果一个结点是红色的,则它的两个子节点都是黑色的

5、对每个结点,从该节点到其所以后代叶节点的简单路径上,均包含相同数目的黑色结点



二、旋转操作

由于树的插入和删除操作会破坏红黑树的性质,为了维护这些性质,必须要改变树中某些结点的颜色以及指针结构,指针结构的修改是通过旋转来完成的,这是一种能保持二叉树搜索性质的搜索树局部操作。


旋转有两种。左旋和右旋

/** * x左旋转 * @param root * @param x */public void Left_Rotate(Node root,Node x){Node y = x.right;x.right = y.left;//把y的左子树赋给x的右子树if(y.left!=null){y.left.p = x;}y.p = x.p;if(x.p==null){root = y;}else if(x==x.p.left){x.p.left = y;}else{x.p.right = y;}y.left = x; //让x成为y的左子树x.p = y;}/** * x右旋转 * @param root * @param x */public void Right_Rotate(Node root,Node x){Node y = x.left;x.left = y.right;if(y.right!=null){y.right.p = x;}y.p = x.p;if(x.p==null){root = y;}else if(x == x.p.left){x.p.left = y;}else{x.p.right = y;}y.right = x;x.p = y;}


三、插入操作

基本上和二叉搜索树的插入一样,只是将插入的z的颜色着红

public void RB_Insert(Node root,Node z){Node y = null;Node x = root;while(x!=null){y = x;if(z.k<x.k){x = x.left;}else{x = x.right;}}z.p = y;if(y==null){root = z;}else if(z.k<y.k){y.left = z;}else{y.right = z;}z.right = null;z.left = null;z.color = "RED";RB_Insert_Fixup(root,z);//调整}

对数据插入后会破坏红黑树的性质,所以需要进行调整。

分为下面三种情况

1、z的叔父结点y是红色的

由于z的父节点z->p和叔节点都是红色,所以z的祖父节点z->p->p的颜色一定是黑色,这是因为插入之前是一颗“完好”的红黑树。

       对于这种情况,处理办法是:将z的父节点和叔节点都染黑,而将z的祖父节点染红,这样做了之后,我们仔细思考一下,发现其实这样对当前树的走父节点或走叔节点的路径的黑节点数没有影响。然后这时我们再将z点指向z的祖父节点位置,然后继续进入循环

2、z的叔父结点y是黑色的,且z是一个右孩子

这里的做法就是将二情况转换成三情况,当然就要用到旋转,但是我们又不希望z的位置发现变化,所以这里先让z=z->p,然后再以z为支点进行左旋,因为左旋会让z下降一级,所以实际上z还是指向的原来那一层的节点,z->p->p的位置还是没有变。

3、z的叔父结点y是黑色的,且z是一个左孩子

这时实际上是z和z->p都是红色,z->p->p和z.->p->right都是黑色,我们想做的就是让z和z->p之间多个黑节点,这样就能满足性质4,但是同时我们又希望保持性质5。于是我们这样处理:

         z->p染黑,z->p->p染红,然后以z->p->p为支点右旋,这样就搞定了



public void RB_Insert_Fixup(Node root,Node z){while(z.p.color=="RED"){if(z.p==z.p.p.left){Node y = z.p.p.right;if(y.color=="RED"){//第一种情况,z的叔父结点为红色z.p.color="BLACK";y.color = "BLACK";z.p.p.color ="RED";z = z.p.p;}else if(z==z.p.right){//第二种情况 z的叔父结点为黑色且z是一个右孩子z = z.p;Left_Rotate(root, z);}else{//第三种情况 z的叔父结点为黑色 且z是一个左孩子z.p.color = "BLACK";z.p.p.color = "RED";Right_Rotate(root, z.p.p);}}else{//same as then clause with "right" and "left" exchangedNode y = z.p.p.left;if(y.color=="RED"){//第一种情况,z的叔父结点为红色z.p.color="BLACK";y.color = "BLACK";z.p.p.color ="RED";z = z.p.p;}else if(z==z.p.left){//第二种情况 z的叔父结点为黑色且z是一个左孩子z = z.p;Right_Rotate(root, z);}else{//第三种情况 z的叔父结点为黑色 且z是一个右孩子z.p.color = "BLACK";z.p.p.color = "RED";Left_Rotate(root, z.p.p);}}}root.color = "BLACK";}




参考《算法导论》

http://blog.csdn.net/cyp331203/article/details/42677833

http://www.cnblogs.com/dongkuo/p/4922058.html







原创粉丝点击