红黑树的实现(Java)

红黑树的实现

红黑树算是一种二叉搜索树的升级版,解决了顺序插入时不会像二叉搜索树那样形成链式的结构,增加了左旋右旋的机制,使二叉树基于平衡。

1. 红黑树的特点

  1. 每个结点不是红色就是黑色。
  2. 不可能有连在一起的红色结点。
  3. 根结点一定为黑色。
  4. 每个红色结点的两个子结点都是黑色。

2. 旋转与颜色变换规则

2.1 颜色变换

当前结点的父亲是红色,且叔叔结点也是红色时:

  1. 把父结点设为黑色
  2. 把叔叔结点设为黑色
  3. 把爷爷结点设为红色
  4. 把指针定义到爷爷结点上,当有违红黑树和特点时再进行变色或旋转
2.2 左旋

当前父结点是红色,叔叔结点为黑色,且当前结点为右子树,以父结点作为左旋。

在这里插入图片描述

2.3 右旋

当前父结点是红色,叔叔结点为黑色,且当前结点为左子树,把父结点变为黑色,把爷爷结点变为红色,以爷爷结点旋转。

在这里插入图片描述

3. 代码实现红黑树(并获取前中后序)

import java.util.ArrayList;
import java.util.List;

/**
 * 红黑树
 * @author wyp
 */
public class RedBlackTree {
    /**
     * 红色
     */
    private final int R = 0;
    /**
     * 黑色
     */
    private final int B = 1;
    /**
     * 根结点
     */
    private Node root;

    /**
     * 内部类表示结点
     */
    private class Node {
        int data;
        int color;
        Node left;
        Node right;
        Node parent;
        Node(int data) {
            this.data = data;
            color = R;
        }
        @Override
        public String toString() {
            return "Node{data=" + data + ", color=" + (color == R ? "red" : "black") + '}';
        }
    }

    /**
     * 获取Node结点
     */
    public Node getInstanceNode(int data) {
        return new Node(data);
    }

    /**
     * 插入值
     * @param data 数值
     */
    public void insert(int data) {
        Node node = new Node(data);

        //插入根结点
        if (root == null) {
            node.color = B;
            root = node;
            return;
        }

        Node parent = root;
        Node son ;

        //左子树
        if (data < parent.data) {
            son = parent.left;
        }else {
            son = parent.right;
        }
        //递归
        while (son != null) {
            parent = son;
            if (data < parent.data) {
                son = parent.left;
            }else {
                son = parent.right;
            }
        }
        if (data < parent.data) {
            parent.left = node;
        }else {
            parent.right = node;
        }
        node.parent = parent;
        //颜色变换
        colorConvert(node);
    }

    /**
     * 颜色变换,使整体符合红黑树规则
     */
    public void colorConvert(Node node) {
        Node parent;
        Node grandpa;
        //当父结点不为空且颜色为红色
        while ((parent = node.parent) != null && parent.color == R) {
            grandpa = parent.parent;
            //如果父亲是爷爷的左子树
            if (grandpa.left == parent) {
                //获取叔叔结点
                Node uncle = grandpa.right;
                //如果叔叔结点不为空且颜色为红色
                if (uncle != null && uncle.color == R) {
                    parent.color = B;
                    uncle.color = B;
                    grandpa.color = R;
                    continue;
                }
                if (node == parent.right) {
                    //左旋
                    leftRotate(parent);
                    //左旋后父子身份互换
                    Node temp = node;
                    node = parent;
                    parent = temp;
                }
                parent.color = B;
                grandpa.color = R;
                //右旋
                rightRotate(grandpa);
            }else {
                //如果父亲是爷爷的右子树
                Node uncle = grandpa.left;
                if (uncle != null && uncle.color == R) {
                    parent.color = B;
                    uncle.color = B;
                    grandpa.color = R;
                    node = grandpa;
                    continue;
                }
                if (node != parent.left) {
                    //右旋
                    rightRotate(parent);
                    //右旋后父子身份互换
                    Node temp = node;
                    node = parent;
                    parent = temp;
                }
                parent.color = B;
                grandpa.color = R;
                //左旋
                leftRotate(grandpa);
            }
        }
        root.color = B;
    }

    /**
     * 左旋
     */
    private void leftRotate(Node node) {
        Node right = node.right;
        Node parent = node.parent;

        if (parent == null) {
            root = right;
            right.parent = null;
        }else {
            if (parent.left != null && parent.left == node) {
                parent.left = right;
            }else {
               parent.right = right;
            }
            right.parent = parent;
        }
        node.parent = right;
        node.right = right.left;
        if (right.left != null) {
            right.left.parent = node;
        }
        right.left = node;
    }

    /**
     * 右旋
     */
    private void rightRotate(Node node) {
        Node left = node.left;
        Node parent = node.parent;

        if (parent == null) {
            root = left;
            left.parent = null;
        }else {
            if (parent.left != null && parent.left == node) {
                parent.left = left;
            }else {
                parent.right = left;
            }
            left.parent = parent;
        }
        node.parent = left;
        node.left = left.right;
        if (left.right != null) {
            left.right.parent = node;
        }
        left.right = node;
    }

    private List<String> beforeList = new ArrayList<>();
    /**
     * 前序遍历
     */
    private void beforeTraversal(Node node) {
        if (node != null) {
            beforeList.add(node.data + "-" + (node.color == R ? "red" : "black"));
            beforeTraversal(node.left);
            beforeTraversal(node.right);
        }
    }
    /**
     * 获取前序遍历后的集合
     */
    public List<String> getBeforeList(RedBlackTree tree) {
        tree.beforeTraversal(tree.getRoot());
        return beforeList;
    }

    private List<String> inList = new ArrayList<>();
    /**
     * 中序遍历
     */
    private void inTraversal(Node node) {
        if (node != null) {
            inTraversal(node.left);
            inList.add(node.data + "-" + (node.color == R ? "red" : "black"));
            inTraversal(node.right);
        }
    }
    /**
     * 获取中序遍历后的集合 格式:值-颜色
     */
    public List<String> getInList(RedBlackTree tree) {
        tree.inTraversal(tree.getRoot());
        return inList;
    }

    private List<String> afterList = new ArrayList<>();
    /**
     * 后序遍历
     */
    private void afterTraversal(Node node) {
        if (node != null) {
            afterTraversal(node.left);
            if (node.right != null) {
                afterTraversal(node.right);
            }
            afterList.add(node.data + "-" + (node.color == R ? "red" : "black"));
        }
    }
    /**
     * 获取后序遍历后的集合
     */
    public List<String> getAfterList(RedBlackTree tree) {
        tree.afterTraversal(tree.getRoot());
        return afterList;
    }
//省略getter/setter...
}

测试:测试:将数组{10,8,12,5,9,1,6,7,6}转换为二叉搜索树并获取前中后序遍历。

在这里插入图片描述

public static void main(String[] args) {
    int[] nums = {10,8,12,5,9,1,6,7,6};
    RedBlackTree tree = new RedBlackTree();
    for (int num : nums) {
        tree.insert(num);
    }
    System.out.println("前序遍历:" + tree.getBeforeList(tree));
    System.out.println("中序遍历:" + tree.getInList(tree));
    System.out.println("后序遍历:" + tree.getAfterList(tree));
}

输出结果:

前序遍历:[8-black, 5-red, 1-black, 6-black, 6-red, 7-red, 10-red, 9-black, 12-black]
中序遍历:[1-black, 5-red, 6-red, 6-black, 7-red, 8-black, 9-black, 10-red, 12-black]
后序遍历:[1-black, 6-red, 7-red, 6-black, 5-red, 9-black, 12-black, 10-red, 8-black]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小辰~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值