package normalTest;
import sun.text.resources.cldr.ig.FormatData_ig;
import javax.jnlp.SingleInstanceListener;
public class segment_tree {
// 弥补前缀和在更新某一个元素之后,需要重新更新正哥前缀和数组
// 通过线段树
private int[] array = {1, 3, 5, 7, 9, 11};
private int[] tree;
public void initTree(){
tree = new int[treeNodes(array.length)];
}
public int treeNodes(int nums){
// 根据原始数组的长度来计算出线段树总共节点的个数
for(int i=1;;i<<=1){
if (i>=nums){
return 2*i-1;
}
}
}
// start, end 用来控制array数组区间索引
// index: Tree数组的索引
public void buildTree(int start, int end, int index){
if(start==end){
// 只有一个元素,表示到达了叶子节点
tree[index] = array[start];
}else{
/*
首先不断二分,直至区间只剩一个元素,此时该区间必然对应线段树的叶子节点——走if代码块,随后递归回溯;
当left、right都回溯完毕,证明当前节点的左、右两个儿子都已经存好了值,作为他们的父节点,我只需加和即可;之后当前函数结束,为上级调用者加和做准备。
*/
// 二分
int mid = (start+end) / 2;
// 计算当前节点的左右儿子索引
int left = 2 * index + 1;
int right = 2 * index + 2;
buildTree(start, mid, left);
buildTree(mid+1, end, right);
// 回溯加和
tree[index] = tree[left] + tree[right];
}
}
// 修改操作
// start,end: 控制array区间的索引
// index: tree数组与[start, end]对应的索引
// oriIndex : array数组等待更新的索引
// val : array[oriIndex]的新值
public void update(int start, int end, int index, int oriIndex, int val){
// 叶子节点,直接更新数据
if (start == end){
array[oriIndex] = val;
tree[index] = val;
}else{
int mid = (start + end) / 2;
int left = 2 * index + 1;
int right = 2 * index + 2;
// 如果oriIndex在左边
if(oriIndex<=mid){
update(start, mid, left, oriIndex, val);
}else{
update(mid+1, end, right, oriIndex, val);
}
// 回溯更新路径节点
tree[index] = tree[left] + tree[right];
}
}
/*
start, end: array 区间对应的索引
index: tree数组与[start, end] 对应的索引
from, to: 查询区间
*/
public int sum(int start, int end, int index, int from, int to){
// 如果查询的区间偏离当前的区间
if (start>to || from>end){
return 0;
}
// 如果查询的区间完全包含当前区间
if (from<=start && to>=end){
return tree[index];
}
// 二分
int mid = (start + end) / 2;
int left = 2 * index + 1;
int right = 2 * index + 2;
return sum(start, mid, left, from, to) + sum(mid+1, end, right, from, to);
}
public static void main(String[] args) {
// 构建一颗segment tree
segment_tree tree = new segment_tree();
tree.initTree();
tree.buildTree(0, 5, 0);
int ans = tree.sum(0, 5, 0, 1, 3);
System.out.println(ans);
}
}
Java实现线段树
最新推荐文章于 2024-04-18 00:57:39 发布