做题时经常会遇到自区间查询的问题,这里我们引用经典的题目:
在一个长度为n的数组中(无序的),查找某个子区间中的最小值。
如果用普通方式写,需要有O(n^2)的处理时间,O(1)的查找效率,但是如果用线段树则是O(n)构造时间,logn的查询时间。
在这里我定义一个线段树T:
#define N 10
#define INFINITE 99999999
int arr[N] = {2,5,6,12,4,1,3,23,43,0};
int T[N];
//线段树
//i为起始角标,j为末尾角标
void createTree(int root,int i,int j){
if(i==j){
T[root] = arr[i];
}else{
int mid = (i + j) / 2;
createTree(root * 2 + 1,i,mid);
createTree(root * 2 + 2,mid+1,j);
T[root] = min(T[root*2+1],T[root*2+2]);
}
}
//i,j为当前区间,ii,jj为需要查询的区间
int query(int root,int i,int j,int ii,int jj){
if(jj < i || ii > j)return INFINITE;
if(i >= ii && j <= jj)return T[root];//如果当前区间为需要查询的区间内,则返回该数
int mid = (i + j) / 2;
return min(query(root*2+1,i,mid,ii,jj),query(root*2+2,mid+1,j,ii,jj));//折半后分2边查找最小值
}
节点的更新:
void updateNode(int root,int i,int j,int index,int value){
if(i==j){
if(index == i)T[root] = value;
}else{
int mid = (i + j) / 2;
if(index <= mid)
updateNode(root*2+1,i,mid,index,value);
else
updateNode(root*2+2,mid+1,j,index,value);
T[root] = min(T[root*2+1],T[root*2+2]);//根据回溯,可以从根据已修改的节点来判断出最大最小值。
}
}
完整代码:
#include
#include
using namespace std;
#define N 10
#define INFINITE 99999999
int arr[N] = {2,5,6,12,4,1,3,23,43,0};
int T[N];
//线段树
//i为起始角标,j为末尾角标
void createTree(int root,int i,int j){
if(i==j){
T[root] = arr[i];
}else{
int mid = (i + j) / 2;
createTree(root * 2 + 1,i,mid);
createTree(root * 2 + 2,mid+1,j);
T[root] = min(T[root*2+1],T[root*2+2]);
}
}
void updateNode(int root,int i,int j,int index,int value){
if(i==j){
if(index == i)T[root] = value;
}else{
int mid = (i + j) / 2;
if(index <= mid)
updateNode(root*2+1,i,mid,index,value);
else
updateNode(root*2+2,mid+1,j,index,value);
T[root] = min(T[root*2+1],T[root*2+2]);//根据回溯,可以从根据已修改的节点来判断出最大最小值。
}
}
//i,j为当前区间,ii,jj为需要查询的区间
int query(int root,int i,int j,int ii,int jj){
if(jj < i || ii > j)return INFINITE;
if(i >= ii && j <= jj)return T[root];//如果当前区间为需要查询的区间内,则返回该数
int mid = (i + j) / 2;
return min(query(root*2+1,i,mid,ii,jj),query(root*2+2,mid+1,j,ii,jj));//折半后分2边查找最小值
}
void print(){
for(int i = 0;iprintf("%d ",arr[i]);
printf("\n");
}
int main(){
createTree(0,0,N-1);
int start = 0;
int end = 9;
print();
printf("[%d - %d]的最小子值为%d",start+1,end+1,query(0,0,N-1,start,end));
}