数据结构--红黑树

来源:互联网 发布:淘宝达人电脑端入口 编辑:程序博客网 时间:2024/06/05 00:18

1、基本概念

红黑树是二叉查找树的一种,与平衡查找树类似,但红黑树的平衡性不像平衡树那样严格。

红黑树的特点:

  • 任何一个节点都有颜色,黑色或者红色
  • 根节点是黑色的
  • 父子节点之间不能出现两个连续的红节点
  • 任何一个节点向下遍历到其子孙的叶子节点,所经过的黑节点个数必须相等
  • 空节点被认为是黑色的

红黑树的基本操作插入、删除、遍历。内容操作和平衡树一样,左右旋转。
这里写图片描述

public class Test {    private static Node root;    private static final boolean RED = false;    private static final boolean BLACK = true;    static class Node{        int data;        Node left;        Node right;        Node parent;        boolean color;        public Node(int data) {            this.data = data;            this.color = BLACK;        }    }    public static void main(String[] args) {        int[] src = { 10, 40, 30, 60, 90, 70, 20, 50, 80 };        for (int i = 0; i < src.length; i++)            insert(src[i]);        midTrav(root);        System.out.println("\n-----------------------------------");        Node node = searchNode(root, 30);        System.out.println(node.data+"");        remove(node);        midTrav(root);        System.out.println("\n-----------------------------------");    }    /*    *      px                              px     *     /                              /     *    x                              y     *   /  \      --(左旋)-.           / \     *  lx   y                         x  ry     *     /   \                      /  \     *    ly   ry                    lx  ly    * */    private static void leftRotate(Node x) {        Node y = x.right;        // 将 “y的左孩子” 设为 “x的右孩子”;        x.right = y.left;        if(y.left != null)            //将ly的父节点指向x            y.left.parent = x;        //将y的父节点指向px        y.parent = x.parent;        //为y指定父节点        if(x.parent == null)            root = y;//x的父节点为空 表示x为根节点        else            //如果x为左子树,则让y也为左子树            if(x.parent.left == x)                y.parent.left = y;            else                //如果x为右子树,则让y也为右子树                y.parent.right = y;        //将x的父节点指向y        y.left = x;        x.parent = y;    }    /*     * 对红黑树的节点(y)进行右旋转     *     * 右旋示意图(对节点y进行左旋):     *            py                               py     *           /                                /     *          y                                x     *         /  \      --(右旋)-.             /  \     *        x   ry                          lx   y     *       / \                                  / \     *      lx  rx                               rx  ry     *     */    private static void rightRotate(Node y) {        Node x = y.left;        y.left = x.right;        if (x.right != null)            x.right.parent = y;        x.parent = y.parent;        if (y.parent == null) {            root = x;        } else {            if (y == y.parent.right)                y.parent.right = x;            else                y.parent.left = x;        }        x.right = y;        y.parent = x;    }    private static void remove(Node node) {        Node child, parent;        boolean color;        // 被删除节点的"左右孩子都不为空"的情况。        if ( (node.left!=null) && (node.right!=null) ) {            // 被删节点的后继节点。(称为"取代节点")            // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。            Node replace = node;            // 获取后继节点            replace = replace.right;            while (replace.left != null)                replace = replace.left;            // "node节点"不是根节点(只有根节点不存在父节点)            if (node.parent!=null) {                if (node.parent.left == node)                    node.parent.left = replace;                else                    node.parent.right = replace;            } else {                // "node节点"是根节点,更新根节点。                root = replace;            }            // child是"取代节点"的右孩子,也是需要"调整的节点"。            // "取代节点"肯定不存在左孩子!因为它是一个后继节点。            child = replace.right;            parent = replace.parent;            // 保存"取代节点"的颜色            color = replace.color;            // "被删除节点"是"它的后继节点的父节点"            if (parent == node) {                parent = replace;            } else {                // child不为空                if (child!=null)                    child.parent = parent;                parent.left = child;                replace.right = node.right;                node.right.parent = replace;            }            replace.parent = node.parent;            replace.color = node.color;            replace.left = node.left;            node.left.parent = replace;            if (color == BLACK)                removeFixUp(child, parent);            node = null;            return ;        }        if (node.left !=null) {            child = node.left;        } else {            child = node.right;        }        parent = node.parent;        // 保存"取代节点"的颜色        color = node.color;        if (child!=null)            child.parent = parent;        // "node节点"不是根节点        if (parent!=null) {            if (parent.left == node)                parent.left = child;            else                parent.right = child;        } else {            root = child;        }        if (color == BLACK)            removeFixUp(child, parent);        node = null;    }    private static void removeFixUp(Node node, Node parent) {        Node other;        while ((node==null || node.color==BLACK) && (node != root)) {            if (parent.left == node) {                other = parent.right;                if (other.color == RED) {                    // Case 1: x的兄弟w是红色的                    other.color = BLACK;                    parent.color = RED;                    leftRotate(parent);                    other = parent.right;                }                if ((other.left==null || other.left.color==BLACK) &&                        (other.right==null || other.right.color==BLACK)) {                    // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的                    other.color = RED;                    node = parent;                    parent = node.parent;                } else {                    if (other.right==null || other.right.color==BLACK) {                        // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。                        other.left.color = BLACK;                        other.color = RED;                        rightRotate(other);                        other = parent.right;                    }                    // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。                    other.color = parent.color;                    parent.color = BLACK;                    other.right.color = BLACK;                    leftRotate(parent);                    node = root;                    break;                }            } else {                other = parent.left;                if (other.color == RED) {                    // Case 1: x的兄弟w是红色的                    other.color = BLACK;                    parent.color = RED;                    rightRotate(parent);                    other = parent.left;                }                if ((other.left==null || other.left.color==BLACK) &&                        (other.right==null || other.right.color==BLACK)) {                    // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的                    other.color = RED;                    node = parent;                    parent = node.parent;                } else {                    if (other.left==null || other.left.color==BLACK) {                        // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。                        other.right.color = BLACK;                        other.color = RED;                        leftRotate(other);                        other = parent.left;                    }                    // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。                    other.color = parent.color;                    parent.color = BLACK;                    other.left.color = BLACK;                    rightRotate(parent);                    node = root;                    break;                }            }        }        if (node!=null)            node.color = BLACK;    }    //插入操作    public static void insert(int data){        Node y = null;        Node x = root;        //找到叶子节点        while(x != null) {            y = x;            if(data > x.data)                x = x.right;            else if(data < x.data)                x = x.left;            else                return;        }        //插入        Node node = new Node(data);        node.parent = y;        if(y == null)            root = node;        else            if(node.data > y.data)                y.right = node;            else                y.left = node;        node.color = RED;        //修正红黑树        insertFixUp(node);    }    private static void insertFixUp(Node node) {        Node parent, gparent;        while ((parent=node.parent)!=null && parent.color==RED) {            gparent = parent.parent;            //一、若“父节点”是“祖父节点的左孩子”            if(parent == gparent.left) {                // Case 1条件:父节点和叔叔节点是红色 则父节点、叔叔节点都为黑,祖父节点为红                Node uncle = gparent.right;                if ((uncle!=null) && uncle.color==RED) {                    uncle.color = BLACK;                    parent.color = BLACK;                    gparent.color = RED;                    node = gparent;                    continue;                }                // Case 2条件:叔叔是黑色,且当前节点是右孩子,进行左转换                if (parent.right == node) {                    Node tmp;                    leftRotate(parent);                    tmp = parent;                    parent = node;                    node = tmp;                }                // Case 3条件:叔叔是黑色,且当前节点是左孩子。将父节点为根的子树右旋转                parent.color = BLACK;                gparent.color = RED;                rightRotate(gparent);            } else {                //二、若“z的父节点”是“z的祖父节点的右孩子”                // Case 1条件:叔叔节点是红色                Node uncle = gparent.left;                if ((uncle!=null) && uncle.color==RED) {                    uncle.color = BLACK;                    parent.color = BLACK;                    gparent.color = RED;                    node = gparent;                    continue;                }                // Case 2条件:叔叔是黑色,且当前节点是左孩子                if (parent.left == node) {                    Node tmp;                    rightRotate(parent);                    tmp = parent;                    parent = node;                    node = tmp;                }                // Case 3条件:叔叔是黑色,且当前节点是右孩子。                parent.color = BLACK;                gparent.color = RED;                leftRotate(gparent);            }        }        root.color = BLACK;    }    //中序遍历    public static void midTrav(Node node){        if(node == null)            return;        midTrav(node.left);        System.out.print(node.data + "    ");        midTrav(node.right);    }    //查找    public static Node searchNode(Node node, int data){        while(node != null)            if(data > node.data)                node = node.right;            else if(data < node.data)                node = node.left;            else                return node;        return node;    }}

如果需要存储多个相同数据,Node中可以添加一个count字段,存放数量

参考:
http://www.cnblogs.com/skywang12345/p/3624343.html
http://blog.csdn.net/tcorpion/article/details/54968644

原创粉丝点击