引言
线段树是一种高级数据结构,用于解决区间查询和更新问题。它在许多应用中都有广泛的使用,例如数组区间的求和、最小值/最大值查询、区间的最小公倍数/最大公约数查询等。本文将详细介绍线段树的定义、构建、应用以及代码实现。
目录
线段树的定义
线段树(Segment Tree)是一种二叉树,用于存储数组区间的信息。每个节点代表一个区间,存储该区间的一些信息,例如区间和、区间最小值或最大值。线段树具有以下性质:
- 每个叶子节点表示数组的一个元素。
- 每个非叶子节点表示其子节点所表示区间的并集。
- 线段树的高度为 (O(\log n)),其中 (n) 是数组的长度。
线段树的应用
线段树主要用于以下应用场景:
- 区间查询:如区间和查询、区间最小值/最大值查询。
- 区间更新:如单点更新、区间更新。
- 其他复杂查询:如区间的最小公倍数/最大公约数查询、区间的差值等。
线段树的构建
线段树的构建过程包括以下步骤:
- 初始化:根据数组长度确定线段树的大小,并初始化线段树数组。
- 构建节点:递归构建线段树节点,每个节点存储对应区间的信息。
线段树的操作
查询操作
查询操作用于在给定的区间内查询一些信息,例如区间和、区间最小值/最大值。查询操作的时间复杂度为 (O(\log n))。
更新操作
更新操作用于修改数组中的某个元素或某个区间的值,并更新线段树中相关节点的信息。更新操作的时间复杂度为 (O(\log n))。
线段树的实现
代码实现
下面是用Java实现线段树的代码示例:
public class SegmentTree {
private int[] tree;
private int[] nums;
private int n;
public SegmentTree(int[] nums) {
this.nums = nums;
this.n = nums.length;
this.tree = new int[4 * n];
buildTree(0, 0, n - 1);
}
private void buildTree(int node, int start, int end) {
if (start == end) {
tree[node] = nums[start];
} else {
int mid = (start + end) / 2;
int leftChild = 2 * node + 1;
int rightChild = 2 * node + 2;
buildTree(leftChild, start, mid);
buildTree(rightChild, mid + 1, end);
tree[node] = tree[leftChild] + tree[rightChild]; // 区间和
}
}
public void update(int idx, int val) {
updateTree(0, 0, n - 1, idx, val);
}
private void updateTree(int node, int start, int end, int idx, int val) {
if (start == end) {
nums[idx] = val;
tree[node] = val;
} else {
int mid = (start + end) / 2;
int leftChild = 2 * node + 1;
int rightChild = 2 * node + 2;
if (idx <= mid) {
updateTree(leftChild, start, mid, idx, val);
} else {
updateTree(rightChild, mid + 1, end, idx, val);
}
tree[node] = tree[leftChild] + tree[rightChild]; // 区间和
}
}
public int query(int L, int R) {
return queryTree(0, 0, n - 1, L, R);
}
private int queryTree(int node, int start, int end, int L, int R) {
if (L > end || R < start) {
return 0; // 无效区间
}
if (L <= start && end <= R) {
return tree[node];
}
int mid = (start + end) / 2;