Java 基于2-3 树实现左倾红黑树(插入、删除、遍历、获取最值、遍历)

左倾红黑树在经典红黑树上加了一个限制:红色结点只能是左孩子。建议学习红黑树从2-3树——左倾红黑树——经典红黑树学起,方便理解及进一步学习。下面记录一下我学红黑树的过程及记录:

一、左倾红黑树的定义

左倾红黑树是含有红黑链接并满足下列条件的二叉查找树:

  1. 红链接均为左链接;
  2. 没有任何一个结点同时和两条红链接相连;
  3. 该树是完美黑色平衡的,即任意空链接到根结点的路径上的黑链接数量相同;

下面是红黑树与2-3树的对应关系:
在这里插入图片描述
在这里插入图片描述

二、平衡化

在对红黑树进行一些增删改查的操作后,很有可能会出现红色的右链接或者两条连续红色的链接,而这些都不满足红黑树的定义,所以我们需要对这些情况通过旋转进行修复,让红黑树保持平衡。

1 、左旋

当某个结点的左子结点为黑色,右子结点为红色,此时需要左旋。

前提:当前结点为h,它的右子结点为x;

左旋过程:

  1. 让x的左子结点变为h的右子结点:h.right=x.left;
  2. 让h成为x的左子结点:x.left=h;
  3. 让h的color属性变为x的color属性值:x.color=h.color;
  4. 让h的color属性变为RED:h.color=true;

在这里插入图片描述



2 、右旋

当某个结点的左子结点是红色,且左子结点的左子结点也是红色,需要右旋

前提:当前结点为h,它的左子结点为x;

右旋过程:

  1. 让x的右子结点成为h的左子结点:h.left = x.right;
  2. 让h成为x的右子结点:x.right=h;
  3. 让x的color变为h的color属性值:x.color = h.color;
  4. 让h的color为RED;

在这里插入图片描述


2 、颜色反转

当一个结点的左子结点和右子结点的color都为RED时,也就是出现了临时的4-结点,此时只需要把左子结点和右子结点的颜色变为BLACK,同时让当前结点的颜色变为RED即可。

在这里插入图片描述






红黑树API实现:

package com.xiaojie.tree;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Queue;

/**
 * @author Mrli
 * @date 2020/9/14 14:23
 * 红黑树的实现:结点插入、删除、树深度、前中后序加层次遍历、或取最小最大值
 */
public class RedBlackTree<Key extends Comparable<Key>,Value>{
   
    /**
     * 红黑树结点
     * @param <Key>
     * @param <Value>
     */
    private class Node<Key,Value> {
   
        //存储键
        public Key key;
        //存储值
        private Value value;
        //记录左子结点
        public Node left;
        //记录右子结点
        public Node right;
        //由其父结点指向它的链接的颜色
        public boolean color;

        /**
         * 新建结点构造函数
         * @param key
         * @param value
         * @param left
         * @param right
         * @param color
         */
        public Node(Key key, Value value, Node left, Node right, boolean color) {
   
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
            this.color = color;
        }
    }

    /**
     *根节点
     */
    private Node root;

    /**
     *记录树中元素的个数
     */
    private int N;

    /**
     * 红色结点标识
     */
    private static final boolean RED = true;

    /**
     * 黑色结点标识
     */
    private static final boolean BLACK = false;


    /**
     * 判断当前结点的指向链接是否为红色
     * @param x
     * @return
     */
    private boolean isRed(Node x){
   
        if(x == null) {
   
            return false;
        }
        return x.color == RED;
    }

    /**
     * 左旋调整
     * @param h
     * @return
     */
    private Node rotateLeft(Node h) {
   
        //找出当前结点h的右子结点
        Node x = h.right;
        //让x的左子结点变为h的右子结点
        h.right = x.left;
        //让h成为x的左子结点
        x.left = h;
        //让h的color属性变为x的color属性值
        x.color = h.color;
        //让h的color属性变为RED
        h.color = RED;
        //返回左旋后的结点
        return x;
    }

    /**
     * 右旋调整
     * @param h
     * @return
     */
    private Node rotateRight(Node h) {
   
        //找出当前结点h的左子结点
        Node x = h.left;
        //让x的右子结点变为h的左子结点
        h.left = x.right;
        //让h成为x的右子结点
        x.right = h;
        //让h的color属性变为x的color属性值
        x.color = h.color;
        //让h的color属性变为RED
        h.color = RED;
        //返回右旋后的结点
        return x;
    }

    /**
     * 颜色反转,相当于完成拆分4-结点
     * @param h
     */
    private void flipColors(Node h) {
   
        //当前结点的左右子结点的color属性值都变为黑色
        h.left.color = BLACK;
        h.right.color = BLACK;
        //当前结点变为红色
        h.color = RED;
    }

    /**
     * 在整个树上完成插入操作
     * @param key
     * @param val
     */
    public void put(Key key, Value val) {
   
        //在root整个树上插入key-val,返回root
        root = put(root,key,val);
        //让根结点的颜色变为BLACK
        root.color = BLACK;
    }

    /**
     * 在指定树中,完成插入操作,并返回添加元素后新的树
     * @param h
     * @param key
     * @param val
     * @return
     */
    private Node put(Node h, Key key, Value val){
   
        //如果h为空,则为第一个结点
        if(h == null) {
   
            N++;
            return new Node(key,val,null,null,RED);
        }

        //当前插入节点的key与root根节点key比较
        int cmp = key.compareTo((Key) h.key);

        if(cmp < 0) {
   
            //插入到当前结点的左子树
            h.left = put(h.left,
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值