您的位置:首页 > 理论基础 > 数据结构算法

数据结构学习——线段树

2018-01-11 00:29 369 查看
线段树作为一种二叉搜索树,在处理区间问题上大大提高了效率。

首先我们以一个数组为例构建线段二叉树的示意图:

数组为 a[1...5] = {5, 4, 2, 3, 1}

                                                [1,  5]

                                            /               \

                                       [1, 3]               [4, 5]

                                    /           \           /           \

                               [1, 2]        [3, 3]    [4, 4]       [5, 5]

                               /    \

                         [1, 1]   [2, 2]

如上示意图所示, 每个结点内的主要信息就是数组a的下标范围,如此, 在求区间最值与区间和就十分方便了。

在线段树的操作中,最基本就是构造线段树,以及更新线段树。

下面以求区间和与求区间最小值为例。

首先确定线段树的数据结构:

struct SegTree //使用静态树的方法来保存信息
{
int left, right; // 结点所示区间[l, r]
int minv;//最小值
int sum;//区间和
};

SegTree stree[maxn];//自行定义maxn
然后是建立区间树的函数:

void build(int v, int l, int r) // v为所用的stree节点, l,r表示范围
{
stree[v].left = l;
stree[v].right = r;
if(l == r)
{//区间内只有一个值时,最小值和区间和便确定了
stree[v].sum = A[l];
stree[v].minv = A[l];
}
else
{//递归构造,并更新sum与minv
int mid = (l + r) / 2;
build(2 * v, l, mid);
build(2 * v + 1, mid + 1, r);
stree[v].sum = stree[v*2].sum + stree[v*2+1].sum;
stree[v].minv = min(stree[v*2].minv, stree[v*2+1].minv);
}
}
build(1, 1, n);

线段树更新:

void update(int id, int pos, int x) //id为其实stree的下标,pos为要更新a[i]的下标, x为要更新的值
{
if(stree[id].left == stree[id].right)//区间只有一个数时,直接完成更新
{
A[stree[id].left] = x;
stree[id].minv = x;
stree[id].sum = x;
}
else
{    //根据 l, r分别向左右进行搜索
int mid = (stree[id].left + stree[id].right) / 2;
if(pos <= mid) update(id * 2, pos, x);
else update(id * 2 + 1, pos, x);
stree[id].sum = stree[id*2].sum + stree[id*2+1].sum;
stree[id].minv = min(stree[id*2].minv, stree[id*2+1].minv);
}
}
update(1, pos, v);


求区间和:

int findSum(int root, int l, int r)

{
if(stree[root].left >= l && stree[root].right <= r) // 当节点区间包含在[l, r] 中时,直接返回区间和
{
return stree[root].sum;
}
else
{//分别计算左右子树的区间和

9e7d
int sumL = 0, sumR = 0;
int mid = (stree[root].left + stree[root].right) / 2;
if(l <= mid)
sumL = findSum(root * 2, l, r);
if(r > mid)
sumR = findSum(root * 2 + 1, l, r);
return sumL + sumR;
}
}

求区间最小值:

int findmin(int root, int l, int r) // root为树根, l, r为指定区间
{
if(stree[root].left >= l && stree[root].right <= r) //区间中只有一个数时,直接返回
{
return stree[root].minv;
}
else
{//分别查找左右子树
int minL = INF, minR = INF;
int mid = (stree[root].left + stree[root].right) / 2;
if(l <= mid)
minL = findmin(root * 2, l, r);
if(r > mid)
minR = findmin(root * 2 + 1, l, r);
return min(minL, minR);//返回最小值
}
}
运用以上代码,就基本能在O(log2n)时间内完成相应的操作,提高查找效率。根据要求不同,也可修改对应的数据结构来满足需求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: