封装线段树实现基本功能

线段树封装

1. 结点类TreeNode
/* 树结点*/
function TreeNode(x, y, val) {
    this.x = x;
    this.y = y;
    this.val = val || null;
}
2. 线段树类

通过options可以传入pushUp函数设置父子结点关系,root记录线段树根节点

function SegTree(options) {
    this.left = null;
    this.right = null;
    this.nums = options.nums;//数组
    this.pushUp = options.pushUp;//自定义父子关联的函数
    this.root = this.build(0, this.nums.length - 1);//建立线段树
}
3. 建树
SegTree.prototype.build = function (x, y) {
    if (x === y) {/* 创建叶子结点并返回结点 */
        return new TreeNode(x, y, this.nums[x]);
    }
    /* 创建结点 */
    let node = new TreeNode(x, y);
    /* 创建子结点 */
    let mid = Math.floor(x + y >> 1);
    node.left = this.build(x, mid);
    node.right = this.build(mid + 1, y);
    /* 关联父子结点 */
    this.pushUp(node, node.left, node.right);
    return node;
}
4. 查询
SegTree.prototype.query = function (tgtX, tgtY, node) {
    //默认为root
    node = node || this.root;
    let x = node.x, y = node.y;
    /* 在[tgtX,tgtY]区域内 */
    if (x >= tgtX && y <= tgtY) {
        return node.val;
    }
    /* 将查询到的值进行叠加 */
    let count = 0;
    let m = Math.floor(x + y >> 1);
    if (tgtY <= m)
        count += this.query(tgtX, tgtY, node.left);
    if (tgtX > m)
        count += this.query(tgtX, tgtY, node.right);
    return count;
}
5. 更新
SegTree.prototype.update = function (tgtX, tgtY, val, node) {
    //默认为root
    node = node || this.root;
    if (node.x === node.y) {
        node.val += val;
        return;
    }
    let mid = Math.floor(tgtX + tgtY >> 1);
    if (tgtX <= mid)
        this.update(tgtX, tgtY, val, node.left)
    if (tgtY > mid)
        this.update(tgtX, tgtY, val, node.right);
    /* 更新父节点 */
    this.pushUp(node, node.left, node.right);
}
6. 删除
SegTree.prototype.delete = function (tgtX, tgtY, node) {
    //默认为root
    node = node || this.root;
    if (tgtX >= node.x && tgtY <= node.y) {
        node.val = 0;
        return;
    }
    let mid = Math.floor(tgtX + tgtY >> 1);
    let flagx, flagy;//标识左右结点是否删除
    if (tgtX <= mid) {
        this.delete(tgtX, tgtY, node.left);
        flagx = true;
    }
    if (tgtY > mid) {
        this.delete(tgtX, tgtY, node.right);
        flagy = true;
    }
    /* 更新父节点 */
    this.pushUp(node, node.left, node.right);
    if (flagx) node.left = null;
    if (flagy) node.right = null;
}
测试代码
/* 测试 */
let tree = new SegTree({
    nums: [-2, 1, -3, 4, -1, 2, 1, -5, 4],
    pushUp: (node, xNode, yNode) => {
        node.val = xNode.val + yNode.val;
    }
})
console.log(tree.query(0, 8))//1
tree.update(0, 8, 1)
console.log(tree.query(0, 8))//10
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值