数据结构—线段树(线段树 知乎)

数据结构—线段树(线段树 知乎)

编码文章call10242025-04-28 20:54:179A+A-

简介

线段树是一种高效地维护区间信息(和、最大值、最小值等)的一种树形结构。线段树有两个主要的接口

  • 查询(query),例如求区间和
  • 更新(update),更新某一位置的值,对应的所有区间和将被更新

两者的时间复杂度均为

建树

线段树与最小堆类似,以二叉树来建立,承载的形式是一个数组。但是,线段树的根结点对应的索引是 1;线段树是一颗完满二叉树(full binary tree),每一个非叶子结点都有两个孩子结点,最后一层靠左排列。

叶子结点是奇数

编辑

添加图片注释,不超过 140 字(可选)

叶子结点是偶数

编辑

添加图片注释,不超过 140 字(可选)

完满二叉树的叶子结点个数与非叶子结点个数有一个关系


因此,线段树将原数组的每一个值都放在叶子结点上,自底向上地建树。

void initialize(vector<int> nums) {
    int n = (int)nums.size();
    vector<int> A(n * 2, 0);
    for (int j = n, i = 0; i < n; i++, j++) {
        A[j] = nums[i];
    }
    for (int j = n - 1; j > 0; j--) {
        A[j] = A[j * 2] + A[j * 2 + 1];
    }
}

时间复杂度 ,空间复杂度

查询

线段树每一个非叶子结点都表示一个区间信息,以区间和为例,根结点表示整个区间和。理想情况下,我们希望直接返回一个区间的和,但往往给出的区间边界不是恰好对应一个非叶子结点,这个时候,我们需要将要求的区间分割,求每一个子区间的和,即可得到最终结果。

int sumRange(int left, int right) {
    int sum = 0;
    left += n;
    right += n;
    while (left <= right) {
        if (left % 2 != 0) {
            sum += A[left++];
        }
        if (right % 2 == 0) {
            sum += A[right--];
        }
        left >>= 1;
        right >>= 1;
    }
    return sum;
}

更新

当原数组的一个或若干个数值发生改变时,对应的区间信息也要发生变化,从叶子结点开始更新路径上的所有的结点。以区间和为例

void update(int index, int val) {
    index += n;
    int diff = val - A[index];
    while (index) {
        A[index] += diff;
        index >>= 1;
    }
}
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4