硅基计划4.0 算法 简单实现B树


文章目录


一、原理

二、实现代码

java 复制代码
package BTree;

/**
 * @author pluchon
 * @create 2026-02-12-13:31
 * 作者代码水平一般,难免难看,请见谅
 */
public class Pair<K,V> {
    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() {
        return key;
    }

    public void setKey(K key) {
        this.key = key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }
}
java 复制代码
package BTree;

import java.util.Arrays;

/**
 * @author pluchon
 * @create 2026-02-12
 * 作者代码水平一般,难免难看,请见谅
 */
//简单模拟实现B树
public class MyBTree {
    static class BTreeNode{
        //关键字数组
        private int [] keys;
        //双亲引用
        private BTreeNode parent;
        //孩子数组
        private BTreeNode [] childs;
        //该节点的有效关键字个数
        private int usedSize;
        //为了便于分裂,我们设计多流出一个空间
        public BTreeNode(int capacity) {
            this.keys = new int[capacity];
            this.childs = new BTreeNode[capacity+1];
            this.usedSize = 0;
            DEFAULT_KEYS_COUNT = capacity;
        }
        public BTreeNode() {
            this(DEFAULT_KEYS_COUNT);
        }
    }

    //默认是三叉数
    public static int DEFAULT_KEYS_COUNT = 3;

    //根节点
    private BTreeNode root;

    //插入部分
    public boolean insert(int key) {
        //查看根节点是否为空
        if(root == null){
            root = new BTreeNode(DEFAULT_KEYS_COUNT);
            root.keys[0] = key;
            root.usedSize++;
            return true;
        }
        //如果根节点不为空,看当前key值是否已经存在
        Pair<BTreeNode, Integer> result = find(key);
        if(result.getValue() != -1){
            return false;
        }
        //开始正式插入
        BTreeNode parent = result.getKey();
        //先把当前节点进行插入排序
        insertkey(parent, key);
        //插入完毕后判断有没有满
        if(parent.usedSize >= DEFAULT_KEYS_COUNT){
            split(parent);
        }
        return true;
    }

    //寻找该key值是否已经插入
    public Pair<BTreeNode,Integer> find(int key){
        BTreeNode parent = null;
        BTreeNode current = root;
        while(current != null){
            int index = 0;
            while(index < current.usedSize){
                if(current.keys[index] == key){
                    return new Pair<>(current,index);
                }else if(current.keys[index] < key){
                    index++;
                }else{
                    break;
                }
            }
            parent = current;
            current = current.childs[index];
        }
        return new Pair<>(parent,-1);
    }

    //插入key值,也就是插入排序
    private void insertkey(BTreeNode node,int key){
        int index = node.usedSize-1;
        while(index >= 0){
            if(node.keys[index] >= key){
                node.keys[index+1] = node.keys[index];
            }else{
                break;
            }
            index--;
        }
        node.keys[index+1] = key;
        node.usedSize++;
    }

    //分裂逻辑
    private void split(BTreeNode current){
        int middle = current.usedSize/2;
        int middleValue = current.keys[middle];
        BTreeNode newNode = new BTreeNode();
        BTreeNode parent = current.parent;
        //复制右半部分到新节点
        int newIndex = 0;
        for(int i = middle+1; i < current.usedSize; i++){
            newNode.keys[newIndex] = current.keys[i];
            newNode.childs[newIndex] = current.childs[i];
            if(newNode.childs[newIndex] != null){
                newNode.childs[newIndex].parent = newNode;
            }
            newIndex++;
        }
        newNode.childs[newIndex] = current.childs[current.usedSize];
        if(newNode.childs[newIndex] != null){
            newNode.childs[newIndex].parent = newNode;
        }
        newNode.usedSize = current.usedSize - middle - 1;
        //清理current右半部分
        for(int i = middle; i < DEFAULT_KEYS_COUNT; i++){
            current.keys[i] = 0;
        }
        for(int i = middle+1; i < DEFAULT_KEYS_COUNT+1; i++){
            current.childs[i] = null;
        }
        current.usedSize = middle;
        if(current == root){
            root = new BTreeNode();
            root.keys[0] = middleValue;
            root.childs[0] = current;
            root.childs[1] = newNode;
            root.usedSize = 1;
            current.parent = root;
            newNode.parent = root;
            return;
        }
        newNode.parent = parent;
        int parentIndex = parent.usedSize-1;
        while(parentIndex >= 0){
            if(parent.keys[parentIndex] >= middleValue){
                parent.keys[parentIndex+1] = parent.keys[parentIndex];
                parent.childs[parentIndex+2] = parent.childs[parentIndex+1];
            }else{
                break;
            }
            parentIndex--;
        }
        parent.keys[parentIndex+1] = middleValue;
        parent.childs[parentIndex+2] = newNode;
        parent.usedSize++;
        if(parent.usedSize >= DEFAULT_KEYS_COUNT){
            split(parent);
        }
    }

    //===================== 删除部分 =====================
    public boolean remove(int key){
        Pair<BTreeNode, Integer> result = find(key);
        if(result.getValue() == -1){
            return false;
        }
        BTreeNode node = result.getKey();
        int index = result.getValue();
        //如果删除的是非叶子节点
        if(node.childs[0] != null){
            //寻找右子树中的最小值作为后继
            BTreeNode successor = node.childs[index+1];
            while(successor.childs[0] != null){
                successor = successor.childs[0];
            }
            //用后继覆盖当前key
            node.keys[index] = successor.keys[0];
            node = successor;
            index = 0;
        }
        deleteEntry(node,index);
        return true;
    }

    //真正删除叶子节点中的key
    private void deleteEntry(BTreeNode node,int index){
        //移动key
        for(int i = index; i < node.usedSize-1; i++){
            node.keys[i] = node.keys[i+1];
        }
        //移动child
        for(int i = index+1; i <= node.usedSize; i++){
            node.childs[i-1] = node.childs[i];
        }
        node.childs[node.usedSize] = null;
        node.keys[node.usedSize-1] = 0;
        node.usedSize--;
        int minKeys = (DEFAULT_KEYS_COUNT+1)/2 - 1;
        if(node != root && node.usedSize < minKeys){
            fixAfterDeletion(node);
        }
        if(node == root && node.usedSize == 0){
            root = node.childs[0];
            if(root != null){
                root.parent = null;
            }
        }
    }

    //删除后修复
    private void fixAfterDeletion(BTreeNode node){
        BTreeNode parent = node.parent;
        int idx = -1;
        for(int i = 0; i <= parent.usedSize; i++){
            if(parent.childs[i] == node){
                idx = i;
                break;
            }
        }
        if(idx == -1){
            throw new RuntimeException("Structure Corrupted");
        }
        int minKeys = (DEFAULT_KEYS_COUNT+1)/2 - 1;
        //向左借
        if(idx > 0 && parent.childs[idx-1].usedSize > minKeys){
            borrowFromLeft(node,parent.childs[idx-1],parent,idx);
        }
        //向右借
        else if(idx < parent.usedSize && parent.childs[idx+1].usedSize > minKeys){
            borrowFromRight(node,parent.childs[idx+1],parent,idx);
        }
        //合并
        else{
            if(idx > 0){
                merge(parent.childs[idx-1],node,parent,idx-1);
            }else{
                merge(node,parent.childs[idx+1],parent,idx);
            }
        }
    }

    private void borrowFromLeft(BTreeNode node,BTreeNode left,BTreeNode parent,int idx){
        for(int i = node.usedSize; i > 0; i--){
            node.keys[i] = node.keys[i-1];
        }
        for(int i = node.usedSize+1; i > 0; i--){
            node.childs[i] = node.childs[i-1];
        }
        node.keys[0] = parent.keys[idx-1];
        node.childs[0] = left.childs[left.usedSize];
        if(node.childs[0] != null){
            node.childs[0].parent = node;
        }
        parent.keys[idx-1] = left.keys[left.usedSize-1];
        left.childs[left.usedSize] = null;
        left.usedSize--;
        node.usedSize++;
    }

    private void borrowFromRight(BTreeNode node,BTreeNode right,BTreeNode parent,int idx){
        node.keys[node.usedSize] = parent.keys[idx];
        node.childs[node.usedSize+1] = right.childs[0];
        if(node.childs[node.usedSize+1] != null){
            node.childs[node.usedSize+1].parent = node;
        }
        parent.keys[idx] = right.keys[0];
        for(int i = 0; i < right.usedSize-1; i++){
            right.keys[i] = right.keys[i+1];
        }
        for(int i = 0; i < right.usedSize; i++){
            right.childs[i] = right.childs[i+1];
        }
        right.childs[right.usedSize] = null;
        right.usedSize--;
        node.usedSize++;
    }

    private void merge(BTreeNode left,BTreeNode right,BTreeNode parent,int parentIdx){
        left.keys[left.usedSize] = parent.keys[parentIdx];
        int start = left.usedSize+1;
        for(int i = 0; i < right.usedSize; i++){
            left.keys[start+i] = right.keys[i];
            left.childs[start+i] = right.childs[i];
            if(left.childs[start+i] != null){
                left.childs[start+i].parent = left;
            }
        }
        left.childs[start+right.usedSize] = right.childs[right.usedSize];
        if(left.childs[start+right.usedSize] != null){
            left.childs[start+right.usedSize].parent = left;
        }
        left.usedSize += right.usedSize+1;
        for(int i = parentIdx; i < parent.usedSize-1; i++){
            parent.keys[i] = parent.keys[i+1];
            parent.childs[i+1] = parent.childs[i+2];
        }
        parent.childs[parent.usedSize] = null;
        parent.usedSize--;
        int minKeys = (DEFAULT_KEYS_COUNT+1)/2 - 1;
        //如果parent是根节点
        if(parent == root){
            if(parent.usedSize == 0){
                root = left;
                root.parent = null;
            }
            //根节点处理完直接结束
            return;
        }
        //如果不是根节点,才允许继续向上修复
        if(parent.usedSize < minKeys){
            fixAfterDeletion(parent);
        }
    }

    public void printTree() {
        if (root == null) return;
        System.out.print("B-Tree 中序: ");
        inOrder(root);
        System.out.println("\n根节点内容: " + Arrays.toString(Arrays.copyOf(root.keys, root.usedSize)));
    }

    private void inOrder(BTreeNode node) {
        if (node == null) return;
        for (int i = 0; i < node.usedSize; i++) {
            inOrder(node.childs[i]);
            System.out.print(node.keys[i] + " ");
        }
        inOrder(node.childs[node.usedSize]);
    }

    // --- 测试用例 ---
    public static void main(String[] args) {
        MyBTree btree = new MyBTree();
        // 构造一个 3 阶 B 树 (2-3树)
        int[] data = {10, 20, 30, 40, 50, 60, 70};
        for (int x : data) btree.insert(x);
        System.out.println("====== B树测试 ======");
        btree.printTree();
        System.out.println("\n[场景1] 删除 70:");
        btree.remove(70); btree.printTree();
        System.out.println("\n[场景2] 删除 60:");
        btree.remove(60); btree.printTree();
        System.out.println("\n[场景3] 删除 50:");
        btree.remove(50); btree.printTree();
        System.out.println("\n全部删除测试通过!");
    }
}

感谢你的阅读

相关推荐
foundbug9991 小时前
果蝇优化算法(FOA)详解:原理、实现与应用
算法
游乐码1 小时前
c#递归函数
算法·c#
im_AMBER2 小时前
Leetcode 119 二叉树展开为链表 | 路径总和
数据结构·学习·算法·leetcode·二叉树
Eloudy2 小时前
SuiteSparse 的 README
人工智能·算法·机器学习·hpc
DN20202 小时前
当AI开始评估客户的“成交指数”
数据结构·人工智能·python·microsoft·链表
whatever who cares2 小时前
Java Web 架构全组件详解
java·前端·架构
好家伙VCC2 小时前
**标题:发散创新|用Python构建GAN图像生成器:从理论到实战全流程解析**---在深度学习飞速发展的今天,**生成对抗
java·python·深度学习·生成对抗网络
我命由我123452 小时前
Android Studio - 在 Android Studio 中直观查看 Git 代码的更改
android·java·开发语言·git·java-ee·android studio·android jetpack
苏荷水2 小时前
万字总结LeetCode100(持续更新...)
java·算法·leetcode·职场和发展