B树的实现java版

/**
 * @author 李亚杰
 * @date 2024/7/4 上午8:53
 * @description BTree
 */
public class BTree {
    final int MIN_KEY_NUMBER;  //最小key数目
    final int MAX_KEY_NUMBER;  //最大key数目
    Node root;
    int t;//最小度数

    public BTree(int t) {
        this.t = t;
        root = new Node(t);
        MAX_KEY_NUMBER = 2 * t - 1;
        MIN_KEY_NUMBER = t - 1;
    }

    public BTree() {
        this(2);
    }

    private static boolean found(Node node, int key, int i) {
        return i < node.keyNumber && node.keys[i] == key;
    }

    //1.是否存在
    public boolean contains(int key) {
        return root.get(key) != null;
    }

    //2.新增
    public void put(int key) {
        doPut(root, key, null, 0);
    }

    private void doPut(Node node, int key, Node parent, int index) {
        int i = 0;
        while (i < node.keyNumber) {
            if (node.keys[i] == key) {
                //更新
                return;
            }
            if (node.keys[i] > key) {
                break; //找到插入位置  i
            }
            i++;
        }
        if (node.leaf) {
            node.insertKey(key, i);

        } else {
            doPut(node.children[i], key, node, i);
        }
        if (node.keyNumber == MAX_KEY_NUMBER) {
            split(node, parent, index);
        }
    }

    void split(Node left, Node parent, int index) {
        //根节点
        if (parent == null) {
            Node newRoot = new Node(t);
            newRoot.leaf = false;
            newRoot.insertChild(left, 0);
            this.root = newRoot;
            parent = newRoot;
        }
        //创建right节点,把t以后的key和Child都拷贝过去
        Node right = new Node(t);
        right.leaf = left.leaf;
        //拷贝元素
        System.arraycopy(left.keys, t, right.keys, 0, t - 1);
        if (!left.leaf) {
            System.arraycopy(left.children, t, right.children, 0, t);
        }
        right.keyNumber = t - 1;
        left.keyNumber = t - 1;
        //中间的key(t-1处)插入到父节点
        int mid = left.keys[t - 1];
        parent.insertKey(mid, index);
        //right节点作为父节点的孩子
        parent.insertChild(right, index + 1);

    }

    /**
     * 打印树中的所有节点元素
     */
    void print() {
        Node p = root;
        int size = 1;
        LinkedList<Node> queue = new LinkedList<>();
        queue.addLast(p);
        while (!queue.isEmpty()) {
            for (int i = 0; i < size; i++) {
                Node node1 = queue.removeFirst();
                System.out.print(node1);
                if (!node1.leaf) {
                    for (int j = 0; j <= node1.keyNumber; j++) {
                        queue.addLast(node1.children[j]);
                    }
                }
            }
            size = queue.size();
            System.out.println();
        }
    }


    public void remove(int key) {
        doRemove(root, key,null,0);
    }

    /**
     *
     * @param node 被查找的节点
     * @param key  被查找key
     * @param parent 被查找节点的父亲
     * @param index 被查找节点在父亲的索引
     */
    private void doRemove(Node node, int key,Node parent,int index) {
        int i = 0;
        while (i < node.keyNumber) {
            if (node.keys[i] >= key) {
                break;
            }
            i++;
        }
        //找到  i == 待删除的索引
        //未找到  到第i个孩子继续查找
        if (node.leaf) {  //叶子节点
            if (!found(node, key, i)) {//case1  叶子节点,没找到
                return;
            } else {//case2  叶子节点,找到了
                node.removeKey(i);
            }
        } else {//不是叶子节点
            if (!found(node, key, i)) {//case3  非叶子节点,没找到
                doRemove(node.children[i], key,node,i);
            } else {//case4  非叶子节点,找到了
                Node s = node.children[i+1];
                while (!s.leaf){
                    s = s.children[0];
                }
                int skey = s.keys[0];//后继key
                //替换待删除key
                node.keys[i] = skey;
                //删除被替换的key
                doRemove(node.children[i+1],skey,node,i+1);
            }
        }
        if (node.keyNumber < MIN_KEY_NUMBER) {//case5,6 删除后的节点数目  <  下限,调整节点。
        balance(parent,node,index);
        }
    }

    /**
     * 调整树节点
     * @param parent 被调整节点父节点
     * @param x 被调整节点
     * @param i 被调整节点的索引
     */
    private void balance(Node parent,Node x,int i){
        //case6  根节点
        if(x==root){
            if (root.keyNumber==0 && root.children[0]!=null){
                root = root.children[0];
            }
            return;
        }
        Node left = parent.childLeftSibling(i);
        Node right = parent.childRightSibling(i);
        //case  5-1  左边富裕,右旋
        if (left!=null&&left.keyNumber>MIN_KEY_NUMBER){
//            父节点中后继key旋转下来
            x.insertKey(parent.keys[i - 1],0);
            //left最大孩子换爹
            if (!left.leaf){
                x.insertChild(left.removeRightmostChild(),0);
            }
            //left最大key换爹
            parent.keys[i-1] = left.removeRightmostKey();
            return;
        }
        //case  5-2  右边富裕,左旋
        if (right!=null&&right.keyNumber>MIN_KEY_NUMBER){
            x.insertKey(parent.keys[i],x.keyNumber);
            if (!right.leaf){
                x.insertChild(right.removeLeftmostChild(), x.keyNumber);
            }
            parent.keys[i] = right.removeLeftmostKey();
            return;
        }
        //case  5-3  两边都不够,向左合并
        if (left!=null){
            //向左兄弟合并
            //删除自己
            parent.removeChild(i);
//            将父节点key添加的兄弟
            left.insertKey(parent.removeKey(i-1), left.keyNumber);
            //将自己所有元素添加到左兄弟
            x.moveToTarget(left);
        }else {
            //向自己合并
            parent.removeChild(i+1);
            x.insertKey(parent.removeKey(i),x.keyNumber);
            right.moveToTarget(x);
        }

    }
    static class Node {
        int[] keys;//关键字
        Node[] children;//孩子
        int keyNumber;//有效关键字的个数
        boolean leaf = true;//是否是叶子节点
        int t;// 最小度数

        public Node(int t) {
            this.t = t;
            this.children = new Node[2 * t];
            this.keys = new int[2 * t - 1];
        }

        public Node(int[] keys) {
            this.keys = keys;
            this.keyNumber = keys.length;
        }

        @Override
        public String toString() {
            return Arrays.toString(Arrays.copyOfRange(keys, 0, keyNumber));
        }

        //多路查找
        Node get(int key) {
            int i = 0;
            while (i < keyNumber) {
                if (keys[i] == key) {
                    return this;
                }
                if (keys[i] > key) {
                    break;
                }
                i++;
            }
            //如果是叶子节点,说明没有此元素
            if (leaf) {
                return null;
            }
            return children[i].get(key);
        }

        //向keys指定索引处插入key
        void insertKey(int key, int index) {
            System.arraycopy(keys, index, keys, index + 1, keyNumber - index);
            keys[index] = key;
            keyNumber++;
        }

        //向children 指定索引插入child
        void insertChild(Node child, int index) {
            System.arraycopy(children, index, children, index + 1, keyNumber - index);
            children[index] = child;
        }

        //移除指定index处的key
        int removeKey(int index) {
            int t = keys[index];
            System.arraycopy(keys, index + 1, keys, index, --keyNumber - index);
            return t;
        }

        //移除最左边的key
        int removeLeftmostKey() {
            return removeKey(0);
        }

        //移除最右边的key
        int removeRightmostKey() {
            return removeKey(keyNumber - 1);
        }

        //        移除指定index处的Child
        Node removeChild(int index) {
            Node removed = children[index];
            System.arraycopy(children, index + 1, children, index, keyNumber - index);
            return removed;
        }

        Node removeLeftmostChild() {
            return removeChild(0);
        }

        Node removeRightmostChild() {
            return removeChild(keyNumber - 1);
        }

        //index左边的Child
        Node childLeftSibling(int index) {
            return index > 0 ? children[index - 1] : null;
        }

        Node childRightSibling(int index) {
            return index != keyNumber ? children[index + 1] : null;
        }

        void moveToTarget(Node target) {
            int start = target.keyNumber;
            if (!leaf) {
                System.arraycopy(children, 0, target.children, start, keyNumber + 1);
            }
            System.arraycopy(keys, 0, target.keys, start, keyNumber);
            target.keyNumber += keyNumber;
        }
    }
}

测试用例

@Test
    void remove(){
        BTree tree = new BTree(2);
        for (int i = 1; i < 7; i++) {
            tree.put(i);
        }
        tree.print();
        tree.remove(2);
        tree.print();
        tree.remove(6);
        tree.print();
        tree.remove(1);
        tree.print();
        tree.remove(3);
        tree.print();
        tree.remove(4);
        tree.remove(5);
        tree.print();

    }

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

财大彭于晏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值