1.线段树:
- 线段树中,叶子节点为数组的元素,线段树中的其他非叶子节点为区间内的最大或者最小/或者总和(根据具体业务而定)
(1)区间染色问题:有一面墙,长度为n,每次选择一段墙染色,m次操作后,问区间[i,k]有多少次颜色。
(2)区间查询
2.线段树的二叉:
平衡二叉树下,二叉搜索不会退化为链表,平衡二叉树的最大深度与最小深度差距不超过1
3.线段树的实现:
采用数组实现:假如有 n 个元素, 则上一层节点有 n / 2 个节点,故需要 4n 空间
// 使用数组实现线段树
public class Set<E extends Comparable<E>>{
private E[] data;
private E[] tree;
private Merger<E> merger;
public Set(E[] arr, Merger<E> merger){
data = (E[]) Object[arr.length];
for(int i = 0 ; i < arr.length; i++){
data[i] = arr[i];
}
tree = (E[]) Object[4 * arr.length];
// 建立线段树
buildSegTree(0, 0, data.length - 1);
}
public int leftChild(int index){
return 2 * index + 1;
}
public int rightChild(int index){
return 2 * index + 2;
}
public int parent(int index){
return index - 1 / 2;
}
public void buildSegTree(int treeIndex, int l, int r){
if(l == r){
tree[treeIndex] = data[l];
return;
}
// 每次下一个节点都是 [l, mid][mid + 1, r]
int mid = l + (r - l) / 2;
buildSegTree(leftChild(treeIndex), l, mid);
buildSegTree(rightChild(treeIndex), mid + 1, r);
tree[treeIndex] = merger.merge(tree[leftChild(treeIndex)], tree[rightChild(treeIndex)]);
}
// 区间查询
public E Query(int QueryL, int QueryR){
if(QueryL < 0 || QueryL >= data.length || QueryR < 0 || QueryR >=data.length){
throw new IllegealmentException(" out of index");
}
E res = Query(0 , 0, data.length, QueryL, QueryR);
return res;
}
// 从 root 开始,在 [0, data.length - 1] 中查询 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 ,Query R);
}else if(QueryL >= mid + 1){
return query(rightChild(treeIndex), mid+1, r, QueryL, QueryR);
}else{ // QueryL <= mid && QueryR >= mid
return merger.merge(query(leftChild(treeIndex), l, mid, QueryL, mid), query(rightChild(treeIndex), mid+1, r, mid + 1, r));
}
}
// 更改数值,更改数组某index 的元素
public void set(int index, E value){
if(index < 0 || index >= data.length){
throw new IllegalException("out of index");
}
set(0, 0, data.length - 1, index, value);
}
public void set(int treeIndex, int l, int r, int index, E value){
if(l == r){
tree[treeIndex] = value;
}
int mid = l + (r - l) / 2;
if(index >= mid + 1){
set(rightChild(treeIndex), mid + 1, r, index, value);
}else if(index <= mid){
set(leftChild(treeIndex), l, mid, index, value);
}
tree[treeIndex] = merger.merge(tree[leftchild(treeIndex)], tree[rightchild(treeIndex)]);
}
}