划分树
2015-07-24 15:07
148 查看
划分树是一种用线段树作为辅助的数据结构,主要用于在lgn时间内查询区间的第k大数值,其原理是基于快排和归并排序的。
划分树的建树过程可以看做是模拟快排的过程,根节点保存原始数组的信息,同时再另开一个数组保存对原始数组排序好后的信息,然后通过排序好后的数组得到中位数,以中位数为划分依据,将小于中位数的数字划入左孩子,大于中位数的数字划入右孩子,那么等于中位数的数字该如何处理呢?其实既然以中位数为划分依据,就是将中位数及其左边的数划入右边,其它划入左边,保持左右孩子的数字的数目大致相同(可能相差1),因此可以用一个变量记录左边需要划入多少个与中位数相同的数字(即代码中的same),划入后剩下的自然就划入右边。
通过上面可以看出,划分树是分层结构,故用二维数组保存,通常20层就足够了,能应付10W左右的数据。代码如下:
划分树最麻烦的是查询,因为求一个区间的第k值,再往下查询时,要算出查询结果在孩子结点中所在的区间,具体见下图
结合上图和代码看着更清楚些。
划分树的建树过程可以看做是模拟快排的过程,根节点保存原始数组的信息,同时再另开一个数组保存对原始数组排序好后的信息,然后通过排序好后的数组得到中位数,以中位数为划分依据,将小于中位数的数字划入左孩子,大于中位数的数字划入右孩子,那么等于中位数的数字该如何处理呢?其实既然以中位数为划分依据,就是将中位数及其左边的数划入右边,其它划入左边,保持左右孩子的数字的数目大致相同(可能相差1),因此可以用一个变量记录左边需要划入多少个与中位数相同的数字(即代码中的same),划入后剩下的自然就划入右边。
通过上面可以看出,划分树是分层结构,故用二维数组保存,通常20层就足够了,能应付10W左右的数据。代码如下:
const int MAXN=100010; int tree[30][MAXN];//表示每层每个位置的值 int sorted[MAXN];//已经排序的数 int toleft[30][MAXN];//toleft[p][i]表示第i层从1到i有多少个数分入左边 void build(int l,int r,int dep) { if(l==r)return; int mid=(l+r)>>1; int same=mid-l+1;//表示等于中间值而且被分入左边的个数 for(int i=l;i<=r;i++) if(tree[dep][i]<sorted[mid]) same--; int lpos=l; int rpos=mid+1; for(int i=l;i<=r;i++) { if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边 tree[dep+1][lpos++]=tree[dep][i]; else if(tree[dep][i]==sorted[mid]&&same>0) { tree[dep+1][lpos++]=tree[dep][i]; same--; } else //比中间值大分入右边 tree[dep+1][rpos++]=tree[dep][i]; toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数 } build(l,mid,dep+1); build(mid+1,r,dep+1); }
划分树最麻烦的是查询,因为求一个区间的第k值,再往下查询时,要算出查询结果在孩子结点中所在的区间,具体见下图
结合上图和代码看着更清楚些。
//查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间 int query(int L,int R,int l,int r,int dep,int k) { if(l==r)return tree[dep][l]; int mid=(L+R)>>1; int cnt=toleft[dep][r]-toleft[dep][l-1];//[l,r]中位于左边的个数 if(cnt>=k) { //L+要查询的区间前被放在左边的个数 int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; //左端点加上查询区间会被放在左边的个数 int newr=newl+cnt-1; return query(L,mid,newl,newr,dep+1,k); } else { int newr=r+toleft[dep][R]-toleft[dep][r]; int newl=newr-(r-l-cnt); return query(mid+1,R,newl,newr,dep+1,k-cnt); } }
相关文章推荐
- Django开发实战之URLconf详解
- hdu 4278——Faulty Odometer
- 图像处理------高斯一阶及二阶导数计算
- 学习qt遇到不显示菜单栏
- Android—开发自学历程(1)-Activity(2)-生命周期
- 如何将相册中的动态GIF图转化成NSData类型
- nginx 高并发配置参数(转载)
- Jersery——RESTful Web Services in Java,RESTful服务,Jersey+Spring实现REST服务调用
- [leetcode] 217.Contains Duplicate
- HYAppFrame(WinForm框架源码)安装部署指南
- apache kafka中server.properties配置文件参数说明
- hdu 4647
- #pragma comment 的作用
- 正则表达式 学习笔记
- js处理小数
- Java开发中的23种设计模式详解(转)
- ZJUTOJ大数乘
- Node.js的函数返回值
- (转)bat批处理的注释语句
- winform的一些小技巧