线段树
线段是是一种二叉搜索树,它将一段区间划分为若干单位区间,每一个结点都存储着一个区间,它功能强大,支持去捡求和、区间最大值。。。
1.定义一个接口,用来实现区间操作
package com.ff.数据结构.linesigntree;
//融合器
public interface Merger<E> {
E merger(E num1,E num2);
}
2.构造线段树
public class LineSignTree<E>{
E[] data; //存储的数据
E[] treeData; //存储整棵树的数据
Merger<E> merger;
LineSignTree(E[] data,Merger merger){
this.data = data;
this.merger = merger;
//构造线段树
//1.线段树的高度
int height = (int) Math.ceil((Math.log(data.length))/Math.log(2)) + 1;
//2.创建线段树的数组
treeData = (E[])new Object[(int)Math.pow(2,height)-1];
//3.构造线段树
BuildLineSignTree(0,data.length-1,0);
}
private void BuildLineSignTree(int start,int end,int index){
if(start == end){
treeData[index] = data[start];
return;
}
//左子树索引
int leftIndex = index*2+1;
//右子树索引
int rightIndex = index*2+2;
//中间结点
int mid = start+(end - start)/2;
//左子树
BuildLineSignTree(start,mid,leftIndex);
//右子树
BuildLineSignTree(mid+1,end,rightIndex);
//回溯相加
treeData[index] = merger.merger(treeData[leftIndex],treeData[rightIndex]);
}
//对区间进行操作
public E query(int start,int end,int index,int from,int to){
if(start == from && end == to){
return treeData[index];
}
//左子树索引
int leftIndex = index*2+1;
//右子树索引
int rightIndex = index*2+2;
//中间索引
int midIndex = start + (end - start)/2;
//查找的区间不在index结点所表示的区间内
if(from > midIndex){
return query(midIndex+1,end,rightIndex,from,to);
}else if(to <= midIndex){
return query(start,midIndex,leftIndex,from,to);
}else {
//跨区间
return merger.merger(query(start,midIndex,leftIndex,from,midIndex),
query(midIndex+1,end,rightIndex,midIndex+1,to));
}
}
public void update(int start,int end,int index,int oriIndex,E value){
if(start == end){
treeData[index] = data[oriIndex] = value;
return;
}
//左子树索引
int leftIndex = index*2+1;
//右子树索引
int rightIndex = index*2+2;
//中间值
int midIndex = start+(end-start)/2;
if(oriIndex <= midIndex){
update(start,midIndex,leftIndex,oriIndex,value);
}else {
update(midIndex+1,end,rightIndex,oriIndex,value);
}
treeData[index] = merger.merger(treeData[leftIndex],treeData[rightIndex]);
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
for(int i=0; i<treeData.length;i++){
sb.append(treeData[i]);
if(i!=treeData.length-1){
sb.append(",");
}
}
return sb.toString();
}