• 全部
  • 问答

请教一个算法

djj2007 2011-03-08 03:27:10
一个集合c,包含大量(>100w)对象,每个对象包含属性:int value1,int value2。每个对象的valve1和value2是一个随机数,在初始化的时候确定。
然后是非常多次的查询,对于每次给定的两个值m,n,得到集合中 value1 > m && value2 > n 的对象集。

求一个算法可以快速求解
...全文
332 点赞 收藏 15
写回复
15 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
foreverlin1204 2011-03-15
可以离线处理的,问题等价成求二维点坐标上一个点的支配集,离线操作的话可以用树状数组,这个常数远远小于各种平衡树,唯一不好的是这事一个离线的办法
回复
zyl072 2011-03-13
[Quote=引用 13 楼 xsj_guagua 的回复:]

额,我觉得你真的误会了,对于二维的两个元素,我把它视为一个结构体,然后自定义一个比较函数,比如x,y都大的大之类的,然后转化为一维的问题。
可能你没怎么用过stl的泛型算法吧
[/Quote]

不解释。
你直接上代码吧,我给你找反例。
回复
xsj_guagua 2011-03-13
[Quote=引用 10 楼 zyl072 的回复:]
引用 3 楼 xsj_guagua 的回复:

对于100w的数据,按照lz的描述,每个数据8字节,那么数据量大于16m
如果数据量在这个等级上的话,在堆中建立RBtree,或者直接用STL的set,你自己定义一个比较函数也可以做到,就是建树的消耗比较大,而且你要求的只是一个大于m,n的集合,并没要求严格排序,所以用tree有点浪费。要达到你要的集合,先中序遍历树,然后每次只要查询到你要的点……
[/Quote]

额,我觉得你真的误会了,对于二维的两个元素,我把它视为一个结构体,然后自定义一个比较函数,比如x,y都大的大之类的,然后转化为一维的问题。
可能你没怎么用过stl的泛型算法吧
回复
qm4050 2011-03-12
我个人觉得分如果集合是没有排序的,用树形结构用处不是太大。
如果集合是list的,我建义使用多线程。将集合分成多段,每一个线程做一段。(记得同步结果集合)
回复
zyl072 2011-03-11
[Quote=引用 6 楼 lzy18lzy 的回复:]

这个问题,可以转化为线段树问题,只不过是分为四叉了
[/Quote]

仔细思考了一下, 四叉的二维线段数可行,而且更快。 赞6楼!
回复
zyl072 2011-03-11
[Quote=引用 3 楼 xsj_guagua 的回复:]

对于100w的数据,按照lz的描述,每个数据8字节,那么数据量大于16m
如果数据量在这个等级上的话,在堆中建立RBtree,或者直接用STL的set,你自己定义一个比较函数也可以做到,就是建树的消耗比较大,而且你要求的只是一个大于m,n的集合,并没要求严格排序,所以用tree有点浪费。要达到你要的集合,先中序遍历树,然后每次只要查询到你要的点就可以了 O(log2n)
这个问题你可以抽象成……
[/Quote]

请不要把解决一维问题的思路拿来解决二维的问题。
二维的问题在于,对象之间无法进行大小比较。 举例: (2,3) 和 (3,2) 你说两个对象谁大谁小? 既无大小的概念,又谈何排序?
既然二维对象无法排序,所有以上回帖中只要是基于有序为前提的算法都是无效的,包括上面提到的BTree、排序二叉树等。

非得要排序,只能是严格定义 优先按X坐标排,X相等时再按Y坐标排。如此一来进行查找时,可以二分法快速定位到 X > M的位置,但仍然需要对所有的 X>M 进行一次O(N)的遍历,取出其中Y>N的对象。
但显然这是一个低效算法,每次查找的平均复杂度仍然是 O(N)。

========================分割线=====================

说下我的想法,将这些对象看成平面上的坐标点。其实就是给定 任意的(M,N), 求 (M,N) 右上角的所有点。
采用分块方法。假设有100W个点,
初始化:
将整个平面进行分块,分成 10000个块 。
具体分块方式由如下:X坐标轴平均分成100份(按X坐标扫描一遍,每隔1W个点则分出一块)。 Y坐标轴也用同样的方法分成100份。 由此,X坐标方向和Y坐标方向总共被切分成1万个块。每块平均有100个点。
对于每一个块内的元素,分别存两份,一份按X坐标排序,另一份按Y坐标排序。

查找算法
对于任意给定的(M,N) ,先用二分的方法定位出该点所在的
1.显然,该块的右上角所有块都必定是满足条件的,直接将这些块内的元素全部输出。
2.遍历一次该块内部的100个点,得到块内满足条件的点输出。
3.遍历该块右边的所有同一水平线上的块, 对每一个块的Y坐标排序那一份进行二分定位。然后输出所有 Y>N的点
4.遍历该块上面的所有同一竖直线上的块,对每一个块的X坐标排序的那一份进行二分定位,然后输出所有N>X的点

复杂度估计,除去输出的时间,最终用来求结果的复杂度稳定在 O( 100 * LOG(100))。


回复
弦率 2011-03-10
学习了,链表能实现吗
回复
chunjvke 2011-03-10
由于查询次数多,应当对两个属性建索引,
回复
lzy18lzy 2011-03-09
这个问题,可以转化为线段树问题,只不过是分为四叉了
回复
showjim 2011-03-09
相当于一个矩阵找一个角的所有点,4叉树应该可以用
回复
超级大笨狼 2011-03-09
如果是比较大小的话,利用二叉树。
回复
djj2007 2011-03-08
请问下rtree该怎么实现,好像是用于磁盘文件管理的吧
回复
xsj_guagua 2011-03-08
对于100w的数据,按照lz的描述,每个数据8字节,那么数据量大于16m
如果数据量在这个等级上的话,在堆中建立RBtree,或者直接用STL的set,你自己定义一个比较函数也可以做到,就是建树的消耗比较大,而且你要求的只是一个大于m,n的集合,并没要求严格排序,所以用tree有点浪费。要达到你要的集合,先中序遍历树,然后每次只要查询到你要的点就可以了 O(log2n)
这个问题你可以抽象成在一组无序数中寻找第k大的数算法,只不过你这的比较函数要自定义一下,而你要寻找的是比k大的一个区间。
算法导论上有给出这个中位数算法,就是按照快排的划分算法,每划分一次,按照中间点的位置和你要寻找的k数字相比较,如果大,就在当前区间的左半边继续进行划分,如果小,就在当前区间的右半边进行划分,递归进行,这种单次的复杂度为O(n),当你频繁查询的时候,你可以记下上一次的查询位置,以后的每次只要在半边进行划分就可以了,虽然也是O(log2n)但是n平均情况下要比之前的小一半。
回复
绿色夹克衫 2011-03-08
用类似RTree的方式做索引可以,还能实现更复杂的查询
回复
Coolfatman 2011-03-08
如果查询次数少,滚几次就行了。
如果查询次数多,那么实现comparator 把对象排序,然后用2分法定位即可。

如果真的太多。把对象放进数据库,然后建索引,查询就是了。
回复
相关推荐
发帖
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
帖子事件
创建了帖子
2011-03-08 03:27
社区公告
暂无公告