【五十七】【算法分析与设计】IndexTree,IndexTree的作用,IndexTree流程,IndexTree代码

IndexTree作用

给你一个nums数组,实现查询区间和操作+单点更新nums数组操作。

可以使用IndexTree结构实现这两个操作。

IndexTree流程

1.

IndexTree的大小和nums数组大小相同。

2.

IndexTree下标必须从1开始,为了方便也将nums数组的下标一一对应。

3.

IndexTree[1]存储nums[1]。

IndexTree[2]存储nums[1]+nums[2]。

IndexTree[3]存储nums[3]。

IndexTree[4]存储nums[1]+nums[2]+nums[3]+nums[4]。

IndexTree[5]存储nums[5]。

IndexTree[6]存储nums[5]+nums[6]。

IndexTree[7]存储nums[7]。

IndexTree[8]存储nums[1]+nums[2]+nums[3]+nums[4]+nums[5]+nums[6]+nums[7]+nums[8]。

4.

一开始IndexTree[1]存储nums[1],线长度为1。

然后IndexTree[2]应该存储nums[2],如果存储nums[2]线长度为1,前面的线长度也是1,和我的相同,于是合并,线长度为2,表示存储nums[1]+nums[2]。

IndexTree[3]应该存储nums[3],线长度为1,前面线长度是2,不相同,不能合并。因此IndexTree[3]存储nums[3]。

IndexTree[4]应该存储nums[4],线长度为1,前面线长度也为1,相同合并,此时线长度为2,前面线长度为2,合并,此时线长度为4,表示nums[1]+nums[2]+nums[3]+nums[4],因此IndexTree[4]=nums[1]+nums[2]+nums[3]+nums[4]。

IndexTree[5]应该存储nums[5],线长度为1,前面线长度为4,不相同,因此IndexTree[5]=nums[5]。

IndexTree[6]应该存储nums[6],线长度为1,前面线长度为1,相同合并,此时线长度为2,前面线长度为4,不相同不能合并,因此IdnexTree[6]=nums[5]+nums[6]。

IndexTree[7]应该存储nums[7],线长度为1,前面线长度为2,不相同不能合并,因此IndexTree[7]=nums[7]。

IndexTree[8]应该存储nums[8],线长度为1,前面线长度为1,合并,此时线长度为2,前面线长度为2,合并此时线长度为4,前面线长度为4,合并此时线长度为8,表示nums[1]~nums[8],因此IndexTree[8]=nums[1]+nums[2]+nums[3]+nums[4]+nums[5]+nums[6]+nums[7]+nums[8]。

5.

如果我要查询nums数组 1~index区间的前缀和。

在IndexTree中,ret+=tree[index].这是第一个位置.

下一个位置是index-=lowbit(index).

ret+=tree[index].

下一个位置是index-=lowbit(index).

直到index越界为止.

6.

index-=lowbit(index)是什么意思?

首先lowbit(index) <==> index&(-index).

意思是在二进制中,保留最低位的1所代表的值.

index-=lowbit(index)意思是抹去最低位的1.

7.

如果我要单点更新nums数组index位置.加上c,IndexTree应该怎么变化?

首先IndexTree[index]+=c.

下一个位置index+=lowbit(index).

IndexTree[index]+=c.

下一个位置index+=lowbit(index).

直到index越界为止.

index+=lowbit(index)意思是加上最低位的1.

8.

如果要查询left~right区间和.

只需要前缀和right减去前缀和left-1.

9.

需要注意的是下标的映射关系.如果nums下标从0开始,IndexTree里面的下标对应的是1~n的下标.

可以想象IndexTree里面有个arr数组,和nums一样,唯一的区别是下标从1开始,IndexTree对应的是arr数组的下标.

IndexTree代码

 
class IndexTree {
public:
    int size;  // 树的大小
    vector<int> tree;  // 树的内部数据结构,用来存储部分和

    // 构造函数,初始化树的大小
    IndexTree(int _size) {
        size = _size + 1;  // 实际大小比输入大小大1,通常是为了方便处理从1开始的下标

        tree.resize(size);  // 调整内部数组的大小以匹配树的大小
    }

    // 计算低位的函数,用于确定区间的边界
    int lowbit(int i) {
        return i & -i;  // 返回i的最低位的1所对应的值
    }

    // 计算从树的起始位置到给定索引的所有元素的总和
    int sum(int index) {  // 对内的区间下标
        int ret = 0;  // 用于存储和的变量
        while (index > 0) {  // 从给定索引开始向树的根部移动
            ret += tree[index];  // 累加路径上的值
            index -= lowbit(index);  // 移动到下一个区间
        }
        return ret;  // 返回计算出的和
    }

    // 更新树的一个节点,增加一个值
    void add(int index, int d) {  // 对内的区间下标
        while (index <= size) {  // 从给定索引开始,向上更新所有相关的节点
            tree[index] += d;  // 更新当前节点
            index += lowbit(index);  // 移动到下一个需要更新的节点
        }
    }

    // 计算给定区间[l, r]的和
    int range(int l, int r) {  // 对外封装的函数,l和r是外界的区间下标
        return sum(r + 1) - sum(l);  // 通过差分计算区间和
    }
};

int main() {

    vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };  // 初始数组
    IndexTree it(nums.size());  // 创建一个树状数组的实例
    for (int i = 0; i < nums.size(); i++) {
        it.add(i + 1, nums[i]);  // 初始化树状数组,将nums中的元素逐个添加进去
    }

    // 打印从每个元素开始到数组结束的所有区间和
    for (int left = 0; left < nums.size(); left++) {
        for (int right = left; right < nums.size(); right++) {
            cout << it.range(left, right) << " ";  // 输出每个区间的和
        }
        cout << endl;  // 每个起始点后换行
    }
    return 0;
}

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

  • 31
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

妖精七七_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值