線段樹的更新
SegmentTree.java
public void set(int index,E e){
if(index<0||index>=data.length)
throw new IllegalArgumentException("INDEX is illegal");
data[index]=e;
//更新tree
set(0,0,data.length-1,index,e);
}
//在以treeIndex 爲根的線段樹中更新 INDEX 的值爲e
private void set (int treeIndex,int l,int r,int index,E e){
if(l==r&& l==index) {
tree[treeIndex]=e;
return ;
}
int TreeLeftIndex=leftChild(treeIndex);
int TreeRightIndex=rightChild(treeIndex);
int mid=l+(r-l)/2;
if(index<=mid)
set(TreeLeftIndex,l,mid,index,e );
else
set(TreeRightIndex,mid+1,r,index,e );
tree[treeIndex]=merger.merge(tree[TreeLeftIndex],tree[TreeRightIndex]);
}
線段樹的完整框架
public class SegmentTree<E> {
private E[] tree;
private E[] data;
private Merger<E>merger;
public SegmentTree(E[] arr,Merger<E> merger){
this.merger=merger;
data=(E[])new Object[arr.length];
for(int i=0;i<arr.length;i++){
data[i]=arr[i];
}
//用數組表示樹類型結構
tree=(E[])new Object[4*arr.length];
buildSegmentTree(0,0,data.length-1);//線段樹的根結點索引爲0
}
//遞歸構建索引爲樹結點treeindex 對應data區間[l,r]的信息
public void buildSegmentTree(int treeindex,int l,int r){
if(l==r){
tree[treeindex]=data[l];
return;
}
int treeleftchildindex=leftChild(treeindex);
int treerightchildindex=rightChild(treeindex);
int mid=l+(r-l)/2;
buildSegmentTree(treeleftchildindex,l,mid);
buildSegmentTree(treerightchildindex,mid+1,r);
// tree[treeindex]=+
tree[treeindex]=merger.merge(tree[treeleftchildindex],tree[treerightchildindex]);
}
public int getSize(){
return data.length;
}
public E get(int index){
if(index<0||index>=data.length)
throw new IllegalArgumentException("index is illeagal");
return data[index];
}
public int leftChild(int index){
return 2*index +1;
}
public int rightChild(int index){
return 2* index +2;
}
public E query(int queryL,int queryR){
if(queryL<0||queryL>=data.length||queryR<0||queryR>=data.length||queryL>queryR)
throw new IllegalArgumentException("index illegal");
return query(0,0,data.length-1,queryL,queryR);
}
//從線段樹的treeIndex 索引開始在區間data[l:r]查找queryL,queryR 的值
private E query(int treeIndex,int l,int r,int queryL,int queryR){
if(l==queryL && r==queryR){
return tree[treeIndex];
}
int mid=l+(r-l)/2;
if( queryR<=mid)
return query(leftChild(treeIndex),l,mid,queryL,queryR);
else if(queryL>=mid+1)
return query(rightChild(treeIndex),mid+1,r,queryL,queryR);
return merger.merge(query(leftChild(treeIndex),l,mid,queryL,mid),query(rightChild(treeIndex),mid+1,r,mid+1,queryR));}
public void set(int index,E e){
if(index<0||index>=data.length)
throw new IllegalArgumentException("INDEX is illegal");
data[index]=e;
//更新tree
set(0,0,data.length-1,index,e);
}
//在以treeIndex 爲根的線段樹中更新 INDEX 的值爲e
private void set (int treeIndex,int l,int r,int index,E e){
if(l==r&& l==index) {
tree[treeIndex]=e;
return ;
}
int TreeLeftIndex=leftChild(treeIndex);
int TreeRightIndex=rightChild(treeIndex);
int mid=l+(r-l)/2;
if(index<=mid)
set(TreeLeftIndex,l,mid,index,e );
else
set(TreeRightIndex,mid+1,r,index,e );
tree[treeIndex]=merger.merge(tree[TreeLeftIndex],tree[TreeRightIndex]);
}
@Override
public String toString(){
StringBuilder res=new StringBuilder();
res.append('[');
for(int i=0;i<tree.length;i++){
if(tree[i]!=null) res.append(tree[i]);
else res.append("null");
if(i!=tree.length-1) res.append(" ");
}
res.append(']');
return res.toString();
}
}
線段 樹應用場景接口
Merge.java
public interface Merger<E> {
E merge(E a,E b);
}
線段樹的調用
main.java
public class Main {
public static void main(String[] args) {
Integer[] nums={-2,0,3,-5,2,-1};
//匿名類
Merger<Integer> merger=new Merger<Integer>() {
@Override
public Integer merge(Integer a, Integer b) {
return a+b;
}
};
SegmentTree<Integer>segTree=new SegmentTree<>(nums,merger);
SegmentTree<Integer>segTree2=new SegmentTree<>(nums,(a,b)->a+b);//lambda 表達式
System.out.println(segTree.toString());
System.out.println(segTree.query(0,2));
// System.out.println(segTree.query(0,5));
}
}