手写红黑树

手写红黑树

前言

之前也写了一些数据结构但都写完就丢。没记录下来。感觉有点可惜,所以这次想记录一下。本次这个红黑树删除采用的不是传统的和叶子节点交换。而是通过合并两个子树来删除。我借鉴一篇haskell的红黑树。不知道是不是我没仔细看,感觉那篇红黑树实现起来有些漏洞。我上一篇博文也有点。虽然修补一下也没问题。但改来改去就是让人不爽。最后我放弃了blance高度必须减一的性质。思路就清晰多了。

代码

AVL

package cn.lyf.tree;

public class AVL<T extends Comparable<T>> {
    Node<T> root;
    Node<T> roate(Node<T> n, boolean left) {
        if (n == null)
            return null;
        Node<T> t1 = n.get(!left), t2;
        if (t1 == null)
            return n;
        t2 = t1.get(left);
        n.set(!left, t2);
        t1.set(left, n);
        return t1;
    }
}

Node

package cn.lyf.tree;

class Node<T extends Comparable<T>> {
    T val;
    boolean red;
    Node<T> L, R;

    Node(T v) {
        val = v;
    }

    Node(Node<T> L, T val, Node<T> R, boolean red) {
        this.val = val;
        this.L = L;
        this.R = R;
        this.red = red;
    }

    Node<T> get(boolean left) {
        if (left)
            return L;
        return R;
    }

    Node<T> set(boolean left, Node<T> v) {
        if (left)
            return L = v;
        return R = v;
    }
}

RedBlackTree

package cn.lyf.tree;

public class RedBlackTree<T extends Comparable<T>> extends AVL<T> {
    boolean[][] paths = { { true, false }, { false, true }, { true, true }, { false, false } };

    Node<T> dyeing(Node<T> n) {
        if (n.red)
            return n;
        boolean[] lefts = new boolean[2];
        if (!canDyeing(n, lefts))
            return n;
        if (lefts[0] ^ lefts[1])
            n.set(lefts[0], roate(n.get(lefts[0]), lefts[0]));
        n = roate(n, !lefts[0]);
        n.red = true;
        n.L.red = n.R.red = false;
        return n;
    }

    Node<T> ins(Node<T> n, T k) {
        if (n == null)
            return new Node<T>(null, k, null, true);
        if (k == n.val)
            return n;
        if (k.compareTo(n.val) < 0)
            n.L = dyeing(ins(n.L, k));
        else
            n.R = dyeing(ins(n.R, k));
        return n;
    }

    Node<T> merge(Node<T> a, Node<T> b) {
        if (a == null)
            return b;
        if (b == null)
            return a;
        if (a.red && b.red) {
            Node<T> s = merge(a.R, b.L);
            if (s == null || !s.red) {
                a.R = s;
                b.L = a;
                return b;
            }
            a.R = s.L;
            b.L = s.R;
            s.L = a;
            s.R = b;
            return s;
        }
        // 双黑
        if (!a.red && !b.red) {
            a.R = merge(a.R, b.L);
            b.L = a;
            a.red = true;
            return dyeing(b);
        }
        // 异色
        if (a.red) {
            a.R = merge(a.R, b);
            return a;
        } else {
            b.L = merge(a, b.L);
            return b;
        }
    }

    // 优先左右,或右左
    boolean canDyeing(Node<T> n, boolean[] lefts) {
        for (boolean[] path : paths) {
            Node<T> t = n.get(path[0]);
            if (t == null || !t.red)
                continue;
            t = t.get(path[1]);
            if (t == null || !t.red)
                continue;
            lefts[0] = path[0];
            lefts[1] = path[1];
            return true;
        }
        return false;
    }

    Msg blance(Node<T> n, boolean left) {
        Node<T> t = n.get(!left);
        // 父节点为红色
        if (n.red) {
            t.red = true;
            n.red = false;
            return new Msg(dyeing(n), true);
        }
        // 父节点为黑色
        // 兄弟节点为黑色
        if (!t.red) {
            t.red = true;
            n = dyeing(n);
            if (n.red) {
                n.red = false;
                return new Msg(n, true);
            }
            return new Msg(n, false);
        }
        // 兄弟节点为红色
        n.set(!left, roate(t, !left));
        n = roate(n, left);
        t.red = false;
        t.get(!left).red = true;
        n.set(!left, dyeing(t));
        return new Msg(n, true);
    }

    Msg del(Node<T> n, T k) {
        if (n == null)
            return new Msg(null, true);
        if (n.val.equals(k)) {
            Node<T> t = merge(n.L, n.R);
            // 删除的是红色节点
            if (n.red)
                return new Msg(t, true);
            // 删除的是黑色节点
            // 合并后根节点为红色
            if (t != null && t.red) {
                t.red = false;
                return new Msg(t, true);
            }
            // 合并后根节点为null或黑色
            return new Msg(t, false);
        }
        boolean ju = n.val.compareTo(k) > 0;
        Msg res = ju ? del(n.L, k) : del(n.R, k);
        n.set(ju, res.node);
        if (res.isBlance)
            return new Msg(n, true);
        return blance(n, ju);
    }

    public void insert(T k) {
        root = ins(root, k);
        root.red = false;
        root = dyeing(root);
        root.red = false;
    }

    public void delete(T k) {
        root = del(root, k).node;
    }

    class Msg {
        Node<T> node;
        boolean isBlance;

        Msg(Node<T> n, boolean j) {
            node = n;
            isBlance = j;
        }
    }

}

TreeUtil

package cn.lyf.tree;

public class TreeUtil {
    <T extends Comparable<T>> void toMermaid(Node<T> n, StringBuffer sb) {
        if (n == null)
            return;
        toMermaid(n.L, sb);
        String name = n.toString().replace("@", "");
        sb.append(name + "(('" + n.val + "'))\n");
        sb.append("\nclass " + name + " " + (n.red ? "red" : "black"));
        if (n.L != null)
            sb.append("\n" + name + "-->" + n.L.toString().replace("@", ""));
        if (n.R != null)
            sb.append("\n" + name + "-->" + n.R.toString().replace("@", ""));
        sb.append("\n");
        toMermaid(n.R, sb);
    }

    <T extends Comparable<T>> String toMermaid(Node<T> r) {
        StringBuffer sb = new StringBuffer();
        sb.append(
                "\n```mermaid\ngraph TD\nclassDef black fill:#222,color:#fff,stroke:#000,stroke-width:2px;\nclassDef red fill:#f22,color:#fff,stroke:#000,stroke-width:2px;\n");
        toMermaid(r, sb);
        sb.append("\n```\n");
        return sb.toString();
    }
}

RBTest

package cn.lyf.tree;

import java.util.*;

public class RBTest<T extends Comparable<T>> {
    public boolean isRB(Node<T> n) {
        return (Boolean) isRB(n, true)[0];
    }

    void addALL(Node<T> n, List<T> l) {
        if (n == null)return;
        addALL(n.L, l);
        l.add(n.val);
        addALL(n.R, l);
    }

    public boolean isOrder(TreeSet<Integer> s, Node n) {
        List<Integer> l1 = new LinkedList<>(s);
        List<Integer> l2 = new LinkedList<>();
        addALL(n, l2);
        return l1.equals(l2);
    }

    Object[] isRB(Node<T> n, boolean red) {
        if (n == null)
            return new Object[] { true, 0 };
        if (red && n.red)
            return new Object[] { false, 0 };
        int h = n.red ? 0 : 1;
        Object[] r1 = isRB(n.L, n.red);
        Object[] r2 = isRB(n.R, n.red);
        if ((Boolean) r1[0] && (Boolean) r2[0] && (int) r1[1] == (int) r2[1]) 
            return new Object[] { true, (int) r1[1] + h };
        return new Object[] { false, 0 };
    }
}

TreeUtil 类比较有趣。用来可视化树。你可以把字符直接粘贴到Typora就可以显示了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值