数据结构-红黑树

来源:互联网 发布:和孩子一起学编程 编辑:程序博客网 时间: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的儿子为红色,所以最后这个树叶可以被安全删除。

原创粉丝点击