算法7-红黑树的插入与删除

读者盆友,晚上好。

本博客代码示例均来自:算法 Algorithmes Forth Edition
[美] Robert Sedgewick Kevin Wayne 著 谢路云译

前几篇博客顺序的介绍了符号表的各种实现:
我们首先介绍了:无序链表中顺序查找 -》 有序数组中的二分查找

二分查找优缺点:

二分查找优点缺点
查找非常快,已知的最快的方法,复杂度在log N静态的、有序的数据,无法应对动态插入的数据

接着:为了找到克服二分法缺点算法,介绍了二叉查找树,这种数可以支持动态插入,同时它的key还能保持有序(可用二分法查),我们已经前进了一大步,然而二叉查找树也有缺点。

二叉查找树优点缺点
支持动态插入数据,同时还能用二分法根据Key快速查找最坏情况搜索路径上会出现N个节点

因此,我们继续寻找看是否还有克服了二叉查找树最坏情况的算法。
可喜的是,我们找到了:平衡查找树
平衡查找树能时刻保证“平衡”,所以会避免二叉查找树最坏的情况,同时又兼有之前优化后的各种优点,堪称完美。

不过因为平衡二叉树引入了4-节点等概念,为了简化代码,出现了红黑二叉查找树,这种树 简单来说可以和 平衡查找树 “等价”,又可以避免4-节点的操作。所以,这是我们最终想要找到的。

平衡查找树优点缺点
始终平衡,避免了二叉查找树最坏情况搜索路径上会出现N个节点的情况代码复杂,不好理解

好了,最终上今天的代码:

package com.cmh.algorithm;

import static edu.princeton.cs.algs4.StdIn.isEmpty;

/**
 * Author:起舞的日子
 * ate: 2020/4/12 下午10:12
 * 红黑树的插入算法
 */
public class RedBlackBST<Key extends Comparable<Key>, Value> {

    public static final boolean RED = true;
    private static final boolean BLACK = false;

    private Node root;

    private boolean isRed(Node h) {
        if (h == null) {
            return false;
        }
        return h.color;
    }

    private Node rotateLeft(Node h) {
        Node x = h.right;
        h.right = x.left;
        x.left = h;
        x.color = h.color;
        h.color = RED;
        x.N = h.N;
        h.N = 1 + size(h.left) + size(h.right);
        return x;
    }

    private Node rotateRight(Node h) {
        Node x = h.left;
        h.left = x.right;
        x.right = h;
        x.color = h.color;
        h.color = RED;
        x.N = h.N;
        h.N = 1 + size(h.left) + size(h.right);
        return x;
    }

    private void flipColors(Node h) {
        h.color = RED;
        h.left.color = BLACK;
        h.right.color = BLACK;
    }

    private int size() {
        return size(root);
    }

    private int size(Node x) {
        if (x == null) {
            return 0;
        } else {
            return x.N;
        }
    }

    private Node put(Node h, Key key, Value val) {
        /*
        标准的插入操作,和父节点用红链接相连
         */
        if (h == null) {
            return new Node(key, val, 1, RED);
        }
        int cmp = key.compareTo(h.key);
        if (cmp < 0) {
            h.left = put(h.left, key, val);
        } else if (cmp > 0) {
            h.right = put(h.right, key, val);
        } else {
            h.val = val;
        }
        if (isRed(h.right) && !isRed(h.left)) {
            h = rotateLeft(h);
        }
        if (isRed(h.left) && isRed(h.left.left)) {
            h = rotateRight(h);
        }
        if (isRed(h.left) && isRed(h.right)) {
            flipColors(h);
        }
        return h;
    }

    /**
     * 删除最小键
     */
    private Node moveRedLeft(Node h) {
        /*
        假设h结点为红色,h.left和h.left.left都是黑色
        将h.left或者h.left的子结点之一变红
         */
        flipColors(h);
        if (isRed(h.right.left)) {
            h.right = rotateRight(h.right);
            h = rotateLeft(h);
        }
        return h;
    }

    private Node deleteMin(Node h) {
        if (h.left == null) {
            return null;
        }
        if (!isRed(h.left) && !isRed(h.left.left)) {
            h = moveRedLeft(h);
        }
        h.left = deleteMin(h.left);
        return balance(h);
    }

    private Node balance(Node h) {
        if (isRed(h.right)) {
            rotateLeft(h);
        }
        if (isRed(h.left) && isRed(h.left.left)) {
            h = rotateRight(h);
        }
        if (isRed(h.left) && isRed(h.right)) {
            flipColors(h);
        }
        return h;
    }

    public void deleteMin() {
        if (!isRed(root.left) && !isRed(root.right)) {
            root.color = RED;
        }
        root = deleteMin(root);
        if (!isEmpty()) {
            root.color = BLACK;
        }
    }

    /**
     * 删除最大键
     */
    private Node moveRedRight(Node h) {
        /*
        假设结点h为红色,h.right和h.right.left都是黑色
        将h.right或者h.right的子结点之一变红
         */
        flipColors(h);
        if (!isRed(h.left.left)) {
            h = rotateRight(h);
        }
        return h;
    }

    private Node deleteMax(Node h) {
        if (isRed(h.left)) {
            h = rotateRight(h);
        }
        if (h.right == null) {
            return null;
        }
        if (!isRed(h.right) && !isRed(h.right.left)) {
            h = moveRedRight(h);
        }
        h.right = deleteMax(h.right);
        return balance(h);
    }

    public void deleteMax() {
        if (!isRed(root.left) && !isRed(root.right)) {
            root.color = RED;
        }
        root = deleteMax(root);
        if (!isEmpty()) {
            root.color = BLACK;
        }
    }

    /**
     * 红黑树最终的删除操作
     */

    private Node delete(Node h, Key key) {
        if (key.compareTo(h.key) < 0) {
            if (!isRed(h.left) && !isRed(h.left.left)) {
                h = moveRedLeft(h);
            }
            h.left = delete(h.left, key);
        } else {
            if (isRed(h.left)) {
                h = rotateRight(h);
            }
            if (key.compareTo(h.key) == 0 && (h.right == null)) {
                return null;
            }
            if (!isRed(h.right) && !isRed(h.right.left)) {
                h = moveRedRight(h);
            }
            if (key.compareTo(h.key) == 0) {
                h.val = get(h.right, min(h.right).key);
                h.key = min(h.right).key;
                h.right = deleteMin(h.right);
            } else {
                h.right = delete(h.right, key);
            }
        }
        return balance(h);
    }

    public Value get(Key key) {
        return get(root, key);
    }

    private Value get(Node x, Key key) {
        if (x == null) {
            return null;
        }
        int cmp = key.compareTo(x.key);
        if (cmp < 0) {
            return get(x.left, key);
        } else if (cmp > 0) {
            return get(x.right, key);
        } else {
            return x.val;
        }
    }

    public Key min() {
        return min(root).key;
    }

    private Node min(Node x) {
        if (x.left == null) {
            return x;
        }
        return min(x.left);
    }

    private class Node {
        /**
         * key:键
         * val:值
         * left right左右子树
         * N 这棵子树中的结点总数
         * color 由其父节点指向它的链接的颜色
         */
        Key key;
        Value val;
        Node left, right;
        int N;
        boolean color;

        Node(Key key, Value val, int N, boolean color) {
            this.key = key;
            this.val = val;
            this.N = N;
            this.color = color;
        }

        private boolean isRed(Node x) {
            if (x == null) {
                return false;
            }
            return x.color;
        }

    }
}

嗯,下次再会!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值