B-tree B树的JS实现(一):添加元素

本文通过JavaScript实现了一个B树的数据结构,详细展示了如何添加键值,并解释了B树的节点分裂过程。B树是一种自平衡的树,适用于大量数据的存储系统,如文件系统和数据库索引。

话不多说,直接上代码。B树的理论网上太多了,大家自行查找学习吧

const M = 3;

class BTree {
    constructor() {
        /*只需要入口节点,即根节点*/
        this.root = null;
    }
    addKey(key){
        if(this.root === null){
            this.root = new BTreeNode();
            this.root.add(key);
            return 1;
        }
        if(this.root.pages.length === 0){
            this.root.add(key);
            return 1;
        }
        /*一直遍历到叶子节点*/
        let node = this.root;
        while(node.pages.length > 0){
            for(let i in node.keys){
                i = parseInt(i);
                if(key === node.keys[i]){
                    return 0;
                }
                if(key < node.keys[i]){
                    node = node.pages[i];
                    break;
                }else if (key > node.keys[node.keys.length - 1]){
                    node = node.pages[node.pages.length - 1];
                    break;
                }else{
                    node = node.pages[i+1];
                    break;
                }
            }
        }
        node.add(key);
        return 1;
    }
}

class BTreeNode {
    constructor() {
        this.parent = null;
        this.keys = [];
        this.pages = [];
    }
    add(key){
        if(this.keys.length === 0){
            this.keys.push(key);
            return this.keys.length;
        }
        if(this.keys[0] > key){
            /*插入头部*/
            this.keys.unshift(key);
        }else if(this.keys[this.keys.length - 1] < key){
            /*插入尾部*/
            this.keys.push(key);
        }else{
            /*插入中间*/
            for(let i in this.keys){
                if(key < this.keys[i+1] && key > this.keys[i]){
                    this.keys.splice(i, 0, key);
                }
            }
        }
        if(this.keys.length <= M - 1){
            return this.keys.length;
        }
        /*一个节点数ceil(M/2) + 1 <= n <= M - 1*/
        /*当节点数满了后,需要分裂*/
        /*第一种分裂方式,中间的关键字上移
        * ,左右的关键字变成左右子
        * 每次插入的时候肯定都是子节点
        *
        * 分裂后,又可能导致非叶子节点的查出从而导致非叶子节点分裂
        * */
        if(this.parent == null){
            let leftChild = new BTreeNode();
            let rightChild = new BTreeNode();
            leftChild.keys = this.keys.slice(0, Math.floor(this.keys.length/2));
            rightChild.keys = this.keys.slice(Math.floor(this.keys.length/2) + 1, this.keys.length);
            leftChild.parent = this;
            rightChild.parent = this;
            this.keys = [this.keys[Math.floor(this.keys.length/2)]];
            leftChild.pages = this.pages.slice(0, Math.floor(this.pages.length/2));
            rightChild.pages = this.pages.slice(Math.floor(this.pages.length/2), this.pages.length);
            this.pages = [leftChild, rightChild];
        }else{
            /*先将新建的节点连接好,顺序不能错,否则分裂时丢失节点*/
            /*先将一半的key分出去*/
            let leftChild = new BTreeNode();
            leftChild.keys = this.keys.slice(0, Math.floor(this.keys.length/2));
            leftChild.parent = this.parent;
            for(let i in this.parent.pages){
                i = parseInt(i);
                /*将新建的节点连接到父节点的pages上*/
                if(this.parent.pages[i] === this){
                    this.parent.pages.splice(i, 0, leftChild);
                    break;
                }
            }

            /*中间的key给父节点*/
            this.parent.add(this.keys[Math.floor(this.keys.length/2)]);
            /*自己保留右边*/
            this.keys = this.keys.slice(Math.floor(this.keys.length/2) + 1, this.keys.length);

            /*本节点的pages左边分配给左边,保留右边*/
            leftChild.pages =[].concat(this.pages.slice(0, Math.floor(this.pages.length/2)));
            this.pages = [].concat(this.pages.slice(Math.floor(this.pages.length/2), this.pages.length));
        }
    }
}

let btree = new BTree();
btree.addKey(53);
btree.addKey(75);
btree.addKey(139);
btree.addKey(49);
btree.addKey(145);
btree.addKey(36);
btree.addKey(101);
<template> <div class="horizontal-tree-container"> <el-tree class="horizontal-tree" :data="treeData" :props="defaultProps" :indent="0" default-expand-all node-key="id" > <template #default="{ node }"> <div class="custom-node"> <span>{{ node.label }}</span> </div> </template> </el-tree> </div> </template> <script> export default { data() { return { treeData: [ { id: 1, label: '节点 1', children: [ { id: 4, label: '节点 1-1', children: [ { id: 9, label: '节点 1-1-1' }, { id: 10, label: '节点 1-1-2' } ] }, { id: 5, label: '节点 1-2' } ] }, { id: 2, label: '节点 2', children: [ { id: 6, label: '节点 2-1' }, { id: 7, label: '节点 2-2' } ] }, { id: 3, label: '节点 3', children: [ { id: 8, label: '节点 3-1' }, { id: 11, label: '节点 3-2', children: [ { id: 12, label: '节点 3-2-1' }, { id: 13, label: '节点 3-2-2' } ] } ] } ], defaultProps: { children: 'children', label: 'label' } }; } }; </script> <style> /* 全局样式覆盖 */ .horizontal-tree-container { overflow-x: auto; padding: 20px; } .horizontal-tree { display: inline-flex; flex-direction: row; min-width: 100%; } /* 移除默认缩进 */ .horizontal-tree .el-tree-node { display: inline-block; min-width: max-content; vertical-align: top; } /* 移除节点间的垂直间距 */ .horizontal-tree .el-tree-node__content { display: inline-block; padding: 5px 0; height: auto; margin: 0 5px; } /* 子节点容器横向排列 */ .horizontal-tree .el-tree-node__children { display: inline-flex; flex-direction: row; padding-left: 0; margin-left: 0; } /* 移除连接线 */ .horizontal-tree .el-tree-node__children::before, .horizontal-tree .el-tree-node__children::after { display: none; } /* 自定义节点样式 */ .horizontal-tree .custom-node { background-color: #f0f7ff; border: 1px solid #c5d9f1; border-radius: 4px; padding: 8px 12px; margin: 5px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); transition: all 0.3s; white-space: nowrap; } .horizontal-tree .custom-node:hover { background-color: #d9ecff; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } /* 移除默认展开图标 */ .horizontal-tree .el-tree-node__expand-icon { display: none; } /* 添加视觉层级指示器 */ .horizontal-tree .el-tree-node__children > .el-tree-node { position: relative; } .horizontal-tree .el-tree-node__children > .el-tree-node::before { content: ''; position: absolute; top: -15px; left: 50%; width: 1px; height: 15px; background-color: #b4c7e7; } .horizontal-tree .el-tree-node__children > .el-tree-node::after { content: ''; position: absolute; top: -15px; left: 50%; width: 50%; height: 1px; background-color: #b4c7e7; } .horizontal-tree .el-tree-node__children > .el-tree-node:first-child::after { left: 50%; width: 0; } .horizontal-tree .el-tree-node__children > .el-tree-node:last-child::after { width: 50%; } </style> 主节点和子节点加连线
最新发布
12-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值