数据结构-红黑树
来源:互联网 发布:和孩子一起学编程 编辑:程序博客网 时间:2024/06/08 17:07
红黑树是AVL树的变种,对红黑树的操作最坏情况下花费O(logN)的时间。相较于AVL树,红黑树更能用一种非递归的方式实现插入。红黑树是非严格的平衡二叉树,而AVL树是严格的平衡二叉树。
红黑树具有以下特征:
1、每个节点要么是红色,要么是黑色。
2、根节点是黑色。
3、NULL节点为黑色。
4、如果节点是红色,那么子节点必须是黑色。
5、从一个节点到一个null引用的路径必须包含相同的黑色节点数。
接着来看一下如何插入数据:
自底向上的插入
为了维持第5个特点,所以插入的数据必然要是红色。
所谓自底向上的插入,就是先将红色节点插入到树中,再从插入点,逐步向上解决冲突。
①第一种情况:如果插入后,父节点是黑色,那么旧完成插入。
②第二次情况:如果插入后,父节点是红色,父节点的兄弟节点是黑色,那么进行一次单旋转或者之字形旋转,如下图所示。
③第三种情况:如果插入后,父节点和它的兄弟节点都是红色。(下图中双圆圈代表红色)加入我们要将79插入,那么我们将父节点和它的兄弟节点都变成黑色,这样保证了两边路径黑色节点的平和,祖父节点变成红色,这样保证了祖父节点和其兄弟节点路径上黑色节点数的一致。加入祖父节点的父节点是红色,那么将祖父节点的父节点的红色向上过滤。
自顶向下的插入
自顶向下的插入时在节点向下寻找插入点的过偶程中,保证父亲的兄弟节点不是红色的,这样就只需要进行一次单旋转或者之字形旋转。在向下的过程中,当看到有一个节点有两个红色儿子,那么将这两个红色儿子变成黑色,该节点变成红色。这样能保持该子树路径上的黑色节点和兄弟子树相同。如果该节点为根节点,那么该节点不需要变成红色。如果该节点的父亲节点也是红色,那么只需要通过旋转就能解除冲突,不需要将红色节点上滤,因为自顶向下的过程中已经保证了两个兄弟节点不可能都为红色。
插入代码
采用非递归形式插入
package com.creat.redblack;/** * Created by WHZ on 2017/8/13 0013. */public class RedBlackTree<E extends Comparable<? super E>>{ private RedBlackNode<E> root; private static class RedBlackNode<E>{ int color; E element; RedBlackNode<E> left; RedBlackNode<E> right; RedBlackNode<E> father; static final int BLACK = 1; static final int RED = 0; RedBlackNode(E element){ this.element = element; this.father = null; this.left = null; this.right = null; this.color = RedBlackNode.RED; } RedBlackNode(E element, RedBlackNode<E> father){ this.element = element; this.father = father; this.left = null; this.right = null; this.color = RedBlackNode.RED; } RedBlackNode(E element,RedBlackNode<E> father,int color){ this.element = element; this.father = father; this.left = null; this.right = null; this.color = color; } } public void printTree(){ printTree(root); } private void printTree(RedBlackNode<E> node){ if(node != null){ printTree(node.left); System.out.println(node.element+((node.color==1)?"黑色":"红色")); printTree(node.right); } } public void insert(E element){ if(root == null){ root = new RedBlackNode<E>(element,null,RedBlackNode.BLACK); }else { RedBlackNode<E> point = root; int compareResult = element.compareTo(point.element); while(compareResult != 0){ if(isRed(point.left) && isRed(point.right)){ if(point == root){ point.left.color = RedBlackNode.BLACK; point.right.color = RedBlackNode.BLACK; }else { point.color = RedBlackNode.RED; point.left.color = RedBlackNode.BLACK; point.right.color = RedBlackNode.BLACK; if(point.father.color == RedBlackNode.RED){ rotate(point); } } } if(compareResult > 0 ){ if(point.right == null){ point.right = new RedBlackNode<E>(element,point); if(point.color == RedBlackNode.RED){ rotate(point.right); } break; }else { point = point.right; compareResult = element.compareTo(point.element); } }else if (compareResult < 0){ if(point.left == null){ point.left = new RedBlackNode<E>(element,point); if(point.color == RedBlackNode.RED){ rotate(point.left); } break; }else { point = point.left; compareResult = element.compareTo(point.element); } }else { break; } } } } private void rotate(RedBlackNode<E> point) { RedBlackNode<E> father = point.father; RedBlackNode<E> grandfather = father.father; RedBlackNode<E> result = null; if(isLeftNode(father) && isLeftNode(point)){ result = rotateWithLeftChild(grandfather); }else if(isRightNode(father) && isRightNode(point)){ result = rotateWithRightChild(grandfather); }else if(isLeftNode(father) && isRightNode(point)){ result = doubleWithLeftChild(grandfather); }else { result = doubleWithRightChild(grandfather); } if(grandfather == root){ root = result; }else { if(isRightNode(result)){ result.father.right = result; }else { result.father.left = result; } } } private RedBlackNode<E> rotateWithLeftChild(RedBlackNode<E> node){ RedBlackNode<E> left = node.left; node.left = left.right; left.right = node; node.color = RedBlackNode.RED; left.color = RedBlackNode.BLACK; left.father = node.father; node.father = left; if(node.left != null){ node.left.father = node; } return left; } private RedBlackNode<E> rotateWithRightChild(RedBlackNode<E> node){ RedBlackNode<E> right = node.right; node.right = right.left; right.left = node; node.color = RedBlackNode.RED; right.color = RedBlackNode.BLACK; right.father = node.father; node.father = right; if(node.right != null){ node.right.father = node; } return right; } private RedBlackNode<E> doubleWithLeftChild(RedBlackNode<E> node){ node.left = rotateWithRightChild(node.left); return rotateWithLeftChild(node); } private RedBlackNode<E> doubleWithRightChild(RedBlackNode<E> node){ node.right = rotateWithLeftChild(node.right); return rotateWithRightChild(node ); } private boolean isRed(RedBlackNode<E> node){ if(node == null){ return false; }else if(node.color == RedBlackNode.RED){ return true; }else { return false; } } private boolean isBlack(RedBlackNode<E> node){ if(node == null){ return true; }else if(node.color == RedBlackNode.BLACK){ return true; }else { return false; } } private boolean isLeftNode(RedBlackNode<E> node){ RedBlackNode<E> father = node.father; if(father == null){ return false; }else { int compareResult = node.element.compareTo(father.element); if(compareResult < 0){ return true; }else { return false; } } } private boolean isRightNode(RedBlackNode<E> node){ RedBlackNode<E> father = node.father; if(father == null){ return false; }else { int compareResult = node.element.compareTo(father.element); if(compareResult > 0){ return true; }else { return false; } } }}
测试结果:
package com.creat.redblack;/** * Created by Administrator on 2017/8/13 0013. */public class Client { public static void main(String[] args){ RedBlackTree<Integer> tree = new RedBlackTree<Integer>(); tree.insert(30); tree.insert(70); tree.insert(60); tree.insert(15); tree.insert(10); tree.insert(20); tree.insert(80); tree.insert(85); tree.insert(50); tree.insert(65); tree.insert(5); tree.insert(40); tree.insert(55); tree.insert(89); tree.insert(65); tree.printTree(); }}5红色10黑色15黑色20黑色30红色40红色50黑色55红色60黑色65红色70黑色80黑色85黑色89红色
自顶向下的删除
如果需要删除的节点有两个儿子或者只有一个右儿子,那么用右子树上最小的节点代替它,然后删除这个最小节点;
如果需要删除的节点有个左儿子,那么用左子树上最大的节点代替它,然后删除这个最大节点。
但是我们需要保证被删除的这个树叶为红色,所以我们采用一种办法要保证这个找到的树叶为红色。
X为当前指向的节点,我们要确保X是红的,先从根节点(个人理解:这个根节点应该是需要被替换节点的左子树或者右子树的根节点)向下遍历,如果X节点是红的,那么继续向下找,如果X节点不是红的,那么看他儿子是不是红的,如果儿子是红的,那么继续向下找,那么就行如下三种操作的其中一种:
接着继续寻找,最后找到需要被删除的树叶,因为之前的步骤确保了X为红色或者说X的儿子为红色,所以最后这个树叶可以被安全删除。
- 数据结构红黑树
- 数据结构:红黑树
- [数据结构]红黑树
- 数据结构-红黑树
- 数据结构-红黑树
- 【数据结构】红黑树
- 数据结构 - 红黑树
- 数据结构--红黑树
- 【数据结构】红黑树
- 【数据结构】红黑树
- 【数据结构】红黑树
- 数据结构---------红黑树
- 数据结构 红黑树
- 数据结构-红黑树
- 【数据结构】红黑树
- 数据结构--红黑树
- 数据结构--红黑树
- 数据结构-红黑树
- Codeforces #428 (Div. 2) C. Journey (DFS
- Spring-AOP基础知识
- java版poi+excel导入实例1
- 尾递归
- DDNS(花生壳)
- 数据结构-红黑树
- bzoj 1601: [Usaco2008 Oct]灌水(最小生成树)
- Codeforces Round #384 (Div. 2) A. Vladik and flights
- 2017.08.12
- 错误笔记之Can't create table 'xxxx' (errno: 121)
- Ubuntu14.04 /deepin14下apt-get安装Code::Blocks
- 求最短路径算法
- 前端异步请求中后发先到的解决方案
- FTPrep, 36 Valid Sudoku