硅基计划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全部删除测试通过!");
    }
}

感谢你的阅读

相关推荐
NE_STOP6 小时前
MyBatis-配置文件解读及MyBatis为何不用编写Mapper接口的实现类
java
后端AI实验室11 小时前
用AI写代码,我差点把漏洞发上线:血泪总结的10个教训
java·ai
CoovallyAIHub11 小时前
Moonshine:比 Whisper 快 100 倍的端侧语音识别神器,Star 6.6K!
深度学习·算法·计算机视觉
CoovallyAIHub12 小时前
速度暴涨10倍、成本暴降6倍!Mercury 2用扩散取代自回归,重新定义LLM推理速度
深度学习·算法·计算机视觉
CoovallyAIHub12 小时前
实时视觉AI智能体框架来了!Vision Agents 狂揽7K Star,延迟低至30ms,YOLO+Gemini实时联动!
算法·架构·github
CoovallyAIHub13 小时前
开源:YOLO最强对手?D-FINE目标检测与实例分割框架深度解析
人工智能·算法·github
程序员清风13 小时前
小红书二面:Spring Boot的单例模式是如何实现的?
java·后端·面试
belhomme13 小时前
(面试题)Redis实现 IP 维度滑动窗口限流实践
java·面试
CoovallyAIHub13 小时前
OpenClaw:从“19万星标”到“行业封杀”,这只“赛博龙虾”究竟触动了谁的神经?
算法·架构·github