红黑树


平衡二叉树

平衡二叉树(Self-balancing binary search tree) 自平衡二叉查找树 又被称为AVL树(有别于AVL算法)

平衡因子(平衡度):结点的平衡因子是结点的左子树的高度减去右子树的高度。(或反之定义)
平衡二叉树: 每个结点的平衡因子都为 1、-1、0 的二叉排序树。或者说每个结点的左右子树的高度最多差1的二叉排序树。

目的: 平衡二叉树的目的是为了减少二叉查找树层次,提高查找速度

常用实现方法: 有AVL、红黑树、替罪羊树、Treap、伸展树等
平衡二叉树

红黑树

让每个节点的左右子树之间的高度差减小。一种平衡二叉树。

  1. 节点是红色或黑色。
  2. 根节点是黑色。
  3. 每个叶节点(NIL节点,空节点)是黑色的。
  4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。

在这里插入图片描述

将空节点作为叶子节点,在本博客红黑树的变换中的图例中,未将空节点画出来

红黑树的变换

  • 变颜色
  • 左旋
  • 右旋

左旋
转载

右旋

以上两个 gif 图为转载

旋转和颜色变换规则:
  1. 所有插入的点默认为红色
  2. 变颜色的情况:当前结点的父亲是红色,且它的爷爷的另一个子结点(叔叔结点)也是红色∶
    a. 把父节点、叔叔节点设为黑色
    b. 把爷爷设为红色
    c. 把当前指针指向爷爷节点(继续使用 2、3、4进行判断)
  3. 左旋:父节点是红色,叔叔是黑色的时候,且当前节点是右子树左旋以父结点作为左旋的节点。
  4. 右旋:父节点是红色,叔叔是黑色的时候,且当前节点是左子树。右旋
    a. 把父亲变为黑色
    b. 把爷爷变为红色
    c. 以爷爷旋转
示例:

1
在这里插入图片描述
在这里插入图片描述

代码

以下代码主要体现其思想,具体有些情况未考虑!!! 仅作参考!!!

public class Main {

    private final int A = 1;
    private final int B = 0;
    private Node root = null;

    class Node{
        int data;
        int color;
        Node left;
        Node right;
        Node pa;
        public Node(int data)
        {
            this.data = data;
        }
    }

    // 插入节点
    public void insert(Node root, int data)
    {
        if(root.data < data)
        {
            if(root.right == null)
                root.right = new Node(data);
            else
                insert(root.right, data);
        }else
        {
            if(root.left == null)
                root.left  = new Node(data);
            else
                insert(root.left, data);
        }
    }
// 需要修改指向的点 
// 1. E节点的父亲节点的孩子指针的指向(需要考虑是否是root)
// 2. S节点
// 3. E节点
// 4. S和E之间的节点
    
    public void leftRotate(Node node)
    {   // node 节点是 E 节点
        if(node.pa == null) // 当前节点为根节点
        {
            Node E = root;
            Node S = E.right;   // S 节点为空怎么办?
            // 移动S的左子树
            E.right = S.left;
            S.left.pa = E;      // S的左子树为空怎么办?
            // 修改E的pa指针
            E.pa = S;
            // 修改S的pa指针
            S.pa = null;
        }else{
            Node E = node;
            Node S = E.right;        // 为了和动图对应
            if(node == node.pa.left) // 父节点的指针指向 当前节点的右子树
                node.pa.left = E.right;
            else
                node.pa.right = E.right;
            E.right = S.left;       // 移动S的左子树
            S.left.pa = E;          //      S的父亲指针指向E

            S.pa = E.pa;            // 更改S的父亲指针
            E.pa = S;               // 更改E的父亲指针

            S.left = E;             // 更改S的左子树指针
        }
    }
    public void rightRotate(Node node) {   
        // node 节点是 S 节点
        if (node.pa == null) // 当前节点为根节点
        {
            Node S = root;
            Node E = S.left;   // E 节点为空怎么办?
            // 移动 E 的右子树
            S.left = E.right;
            E.right.pa = S;      // E的右子树为空怎么办?
            // 修改 S 的pa指针
            S.pa = E;
            // 修改 E 的pa指针
            E.pa = null;
        } else {
            Node S = node;
            Node E = S.right;        // 为了和动图对应
            if (node == node.pa.left) // 父节点的指针指向 当前节点的右子树
                node.pa.left = S.left;
            else
                node.pa.right = S.left;
            S.left = E.right;       // 移动E的右子树
            E.right.pa = S;          //      E的父亲指针指向S

            E.pa = S.pa;            // 更改E的父亲指针
            S.pa = E;               // 更改S的父亲指针

            E.right = S;             // 更改E的右子树指针
        }
    }
}

leetCode中有个童鞋写的 基于平衡二叉树的不可重复Set

AVL树 & 红黑树的区别

  1. 红黑树并不追求完全平衡——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。
  2. 红黑树能够以O(log2 n) 的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。
  3. 红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高。当然,红黑树并不适应所有应用树的领域。
  4. 如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。
  5. 如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。在实际的系统中,例如,需要使用动态规则的防火墙系统,使用红黑树而不是散列表被实践证明具有更好的伸缩性,典型的用途是实现关联数组。
  6. AVL树是最先发明的自平衡二叉查 找树。在AVL树中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值