数据是动态变化的,而不是静止的对于线段树是好的选择
满二叉树是可以用数组表示的,只需要在上面最后一层补空结点
实现
- SegmentTree.java
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;
}
}
- Merger 接口与具体的应用场景有关
public interface Merger<E> {
E merge(E a,E b);
}
为了显示结果在SegmentTree.java
中加入
@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();
}
测试在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());
}
}
结果如下: