引言
线段树是一种高级数据结构,用于解决区间查询和更新问题。它在许多应用中都有广泛的使用,例如数组区间的求和、最小值/最大值查询、区间的最小公倍数/最大公约数查询等。本文将详细介绍线段树的定义、构建、应用以及代码实现。
目录
线段树的定义
线段树(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;
int leftChild = 2 * node + 1;
int rightChild = 2 * node + 2;
int leftSum = queryTree(leftChild, start, mid, L, R);
int rightSum = queryTree(rightChild, mid + 1, end, L, R);
return leftSum + rightSum;
}
public static void main(String[] args) {
int[] nums = {1, 3, 5, 7, 9, 11};
SegmentTree segmentTree = new SegmentTree(nums);
System.out.println("初始区间和查询(0, 5): " + segmentTree.query(0, 5));
segmentTree.update(1, 10);
System.out.println("更新后区间和查询(0, 5): " + segmentTree.query(0, 5));
}
}
代码解释
-
初始化线段树:
public SegmentTree(int[] nums) { this.nums = nums; this.n = nums.length; this.tree = new int[4 * n]; buildTree(0, 0, n - 1); }
初始化线段树,创建大小为4倍数组长度的线段树数组,并调用
buildTree
方法构建线段树。 -
构建线段树:
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; int leftChild = 2 * node + 1; int rightChild = 2 * node + 2; int leftSum = queryTree(leftChild, start, mid, L, R); int rightSum = queryTree(rightChild, mid + 1, end, L, R); return leftSum + rightSum; }
查询给定区间的和,递归查找并合并子区间的结果。
-
主函数:
public static void main(String[] args) { int[] nums = {1, 3,
5, 7, 9, 11};
SegmentTree segmentTree = new SegmentTree(nums);
System.out.println("初始区间和查询(0, 5): " + segmentTree.query(0, 5));
segmentTree.update(1, 10);
System.out.println("更新后区间和查询(0, 5): " + segmentTree.query(0, 5));
}
```
创建线段树并进行区间查询和更新操作。
图解说明
以下是线段树构建和查询过程的图解:
结论
通过上述讲解和实例代码,我们详细展示了线段树的定义、构建、应用以及操作。线段树是一种强大的数据结构,能够高效地处理区间查询和更新操作,适用于多种场景。希望这篇博客对您有所帮助!
如果您觉得这篇文章对您有帮助,请关注我的CSDN博客,点赞并收藏这篇文章,您的支持是我持续创作的动力!
关键内容总结:
- 线段树的定义和应用
- 线段树的构建和操作
- 线段树的代码实现和图解说明
推荐阅读:深入探索设计模式专栏,详细讲解各种设计模式的应用和优化。点击查看:深入探索设计模式。
特别推荐:设计模式实战专栏,深入解析设计模式的实际应用,提升您的编程技巧。点击查看:设计模式实战。
如有任何疑问或建议,欢迎在评论区留言讨论。谢谢阅读!
标签:node,end,定义,int,线段,tree,start,应用 From: https://blog.csdn.net/qq_40254606/article/details/141038777