线段树的简单实现和查询(修改)

做题时经常会遇到自区间查询的问题,这里我们引用经典的题目:
在一个长度为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));
}

你可能感兴趣的:(算法,数据结构)