一、目标:1.如何快速的查询出下列数组arr[2,5]的和 2。以及更新arr[4]为6。
用普通的方法查询的复杂度为O(n),更新的复杂度为O(1)。
这时候我们可以用线段树来快速完成这些操作,复杂度为logn。
二、内容:如何创建,查询,更新线段树。
public class QurQpd {
public static void main(String[] args) {
int [] arr= {1,3,5,7,9,11};
int [] tree=new int[10000];
build_tree(arr,tree,0,0,5);
System.out.println(qury_tree(arr, tree, 0, 0, 5, 4, 4));
update_tree(arr, tree, 0, 0, 5, 4, 6);
System.out.println(qury_tree(arr, tree, 0, 0, 5, 4, 4));
}
/*
* 创建线段树
*/
static void build_tree(int arr[],int tree[],int node,int start,int end) {
if(start==end) {
tree[node]=arr[start];
}
else {
int mid=(start+end)/2;
int left_node=2*node+1;
int right_node=2*node+2;
build_tree(arr,tree,left_node,start,mid);
build_tree(arr,tree,right_node,mid+1,end);
tree[node]=tree[left_node]+tree[right_node];
}
}
/*
* 查询数组下标[L,R]数组的和。
*/
static int qury_tree(int arr[],int tree[],int node,int start,int end,int L,int R) {
//第一个if要放在前边,不然会出错。原因:加入1,2if调换顺序,不符合条件的节点也会被算进去了。
if(end<L||start>R) {
return 0;
}
else if(start==end) {
return tree[node];
}
else if(start>=L&&end<=R) {
return tree[node];
}
else {
int mid=(start+end)/2;
int left_node=2*node+1;
int right_node=2*node+2;
int a=qury_tree(arr,tree,left_node,start,mid,L,R);
int b=qury_tree(arr,tree,right_node,mid+1,end,L,R);
return a+b;
}
}
/*
* 更新下标为num的值为Val
*/
static void update_tree(int arr[],int tree[],int node,int start,int end,int num,int val) {
if(end==start) {
arr[num]=val;
tree[node]=val;
}
else {
int mid=(start+end)/2;
int left_node=2*node+1;
int right_node=2*node+2;
if(num<=mid)
update_tree(arr, tree, left_node, start, mid, num, val);
if(num>mid)
update_tree(arr, tree, right_node, mid+1, end, num, val);
tree[node]=tree[left_node]+tree[right_node];
}
}
}
- 画出来的线段树:
- 三、总结:
- 写递归函数时,一定要用到if-else或者if-else if-else分支语句,否者函数没有出口。
- 写更新方法的时候一直不明白为什么要用线段树来更新,这样复杂度不久为logn了,不是更复杂吗,为什么不直接修改(复杂度为O(1)。现在想通了,原因是:已经构造了线段树,假如直接修改arr[]的会导致线段树没有同时更新,线段树就是错的。