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

来源:互联网 发布:淘宝上苏泊尔是正品吗 编辑:程序博客网 时间:2024/06/06 03:34

做题时经常会遇到自区间查询的问题,这里我们引用经典的题目:
在一个长度为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<iostream>#include<algorithm>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;i<N;i++)        printf("%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));}