四叉树索引的改进算法

转自:http://blog.sina.com.cn/s/blog_488e2b5b010122yp.html


转:四叉树索引的改进算法

  (2012-04-11 18:49:35)
标签: 

四叉树

 

空间索引

 

gis

 

改进

 

杂谈

分类: GIS相关
         在搞空间索引的东东,找到这个,感觉还不错,就记录一下。


      四叉树索引(Quadtree),类似于前面介绍的网格索引,也是对地理空间进行网格划分,对地理空间递归进行四分来构建四叉树,本文将在普通四叉树的基础上,介绍一种改进的四叉树索引结构。

       首先,先介绍一个GISGeographic Information System)或者计算机图形学上非常重要的概念——最小外包矩形(MBR-Minimum Bounding Rectangle)

 转:四叉树索引的改进算法


         最小外包矩形 MBR 就是包围图元,且平行于 X Y 轴的最小外接矩形。 MBR 到底有什么用处呢,为什么要引入这个概念呢?因为,图元的形状是不规则的,而 MBR 是平行于 X Y 轴的规则图形,设想一下,如果所有的图元都是平行于 X Y 轴的矩形,那针对这样的矩形进行几何上的任何判断,是不是要简单很多呢?不管我们人自己写公式算法或者编写程序运行,是不是都要比原本复杂的图形几何运算要简洁很多呢?答案很显然。

       然后,我们再介绍一下GIS空间操作的步骤(这个步骤,在前面忘记向大家说明了,在这里补充一下)

 转:四叉树索引的改进算法

        可见,过滤阶段,通过空间索引可以排除掉一些明显不符合条件的图元,得到后选集合,然后对后选图元集合进行精确几何运算,得到最终结果。大家可能会有这样的疑问,这样有必要吗?是不是反而把问题复杂化了?合适的空间索引只会提高计算机的效率,没有空间索引,我们无疑要对集合中的每个图元进行精确几何运算,而这样的运算是复杂的,是非常占用CPU的,所以需要空间索引,采取少量的内存和简单的CUP运算,来尽量减少那种高耗CUP的精确运算的次数,这样做是完全值得的。至于精确的几何运算到底复杂在哪里,该如何进行精确的几何运算,将在下面的章节中详细描述,这里主要介绍过滤阶段的空间索引。

       现在,让我们来具体了解一下四叉树索引

 转:四叉树索引的改进算法

四叉树索引就是递归地对地理空间进行四分,直到自行设定的终止条件(比如每个节点关联图元的个数不超过3个,超过3个,就再四分),最终形成一颗有层次的四叉树。图中有数字标识的矩形是每个图元的MBR,每个叶子节点存储了本区域所关联的图元标识列表和本区域地理范围,非叶子节点仅存储了区域的地理范围。大家可以发现,同样存在一个图元标识被多个区域所关联,相应地存储在多个叶子节点上,比如“6“所代表的图元,分别存储在四个分枝上。这样,就存在索引的冗余,与网格索引存在同样的弊端。下面我们介绍一种改进的四叉树索引,或者说是分层的网格索引。

         改进的四叉树索引,就是为了避免这种空间索引的冗余,基本改进思路是:让每个图元的MBR被一个最小区域完全包含

 转:四叉树索引的改进算法

    可以看出,313分别都跨越了两个区域,要被一个最小区域完全包含,就只能是根节点所代表的区域,25跨越了两个区域,6跨越了四个区域,要被一个最小区域完全包含,就只能是NW区域。怎么判断一个图元被哪个最小区域完全包含呢?从直观上看,递归地对地理空间进行四分,如果图元与一个区域四分的划分线相交,则这个图元就归属于这个区域,或者直到不再划分了,那就属于这个不再划分的区域。呵呵。。。可能有点绕口,看图,结合最小”“完全包含这两个字眼,您就明白了。这颗四叉树中,图元的标识不再仅仅存储在叶子节点上,而是每个节点都有可能存储,这样也就避免了索引冗余。同时每个节点存储本节点所在的地理范围。

有了四叉树索引,下面又该如何利用这颗树来帮助检索查找呢?还是矩形选择为例吧!(为什么我总是拿这个例子来说事呢?因为这个例子简单,容易理解,有代表性!)我们在地图上画一个矩形,判断地图上哪些图元落在这个矩形里或者和这个所画矩形相交。方法很多,这里介绍一种简单的检索步骤,如下:1,首先,从四叉树的根节点开始,把根节点所关联的图元标识都加到一个List里;2,比较此矩形范围与根节点的四个子节点(或者叫子区域)是否有交集(相交或者包含),如果有,则把相应的区域所关联的图元标识加到List集合中,如果没有,则以下这颗子树都不再考虑。3,以上过程的递归,直到树的叶子节点终止,返回List4,从List集合中根据标识一一取出图元,先判断图元MBR与矩形有无交集,如果有,则进行下面的精确几何判断,如果没有,则不再考虑此图元。(当然,这里只说了一个基本思路,其实还有其他一些不同的方法,比如,结合空间数据磁盘的物理存储会有一些调整)

    总结:改进的四叉树索引解决了线,面对象的索引冗余,具有较好的性能,而被大型空间数据库引擎所采用,如ArcSDEOracle Spatial等,同时这种结构也适用于空间数据的磁盘索引,配合空间排序聚类,基于分形的Hilbert算法数据组织,将在空间数据格式的定义中发挥重要作用。

   参考文献:

一种基于改进四叉树的GIS空间选择查询算法   杨崇俊 芮小平 高积粮 计算机工程与应用


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
四叉树是一种空间索引结构,它将二维空间划分为四个象限,每个象限可以再继续划分为四个象限,以此类推,直到达到某个终止条件。 在Java中,可以使用以下代码实现四叉树空间索引: 1. 定义QuadTree类 public class QuadTree { private final int MAX_CAPACITY = 4; // 每个节点最大容量 private final int MAX_LEVEL = 5; // 最大深度 private int level; // 当前深度 private List<Point> points; // 当前节点包含的点 private Rectangle boundary; // 当前节点的边界 private QuadTree[] children; // 子节点 public QuadTree(Rectangle boundary, int level) { this.boundary = boundary; this.level = level; points = new ArrayList<>(); children = null; } // 插入点 public boolean insert(Point point) { if (!boundary.contains(point)) { return false; } if (points.size() < MAX_CAPACITY && children == null) { points.add(point); return true; } if (children == null) { split(); } for (QuadTree child : children) { if (child.insert(point)) { return true; } } return false; } // 分裂节点 private void split() { children = new QuadTree[4]; int subWidth = boundary.width / 2; int subHeight = boundary.height / 2; int x = boundary.x; int y = boundary.y; children[0] = new QuadTree(new Rectangle(x + subWidth, y, subWidth, subHeight), level + 1); children[1] = new QuadTree(new Rectangle(x, y, subWidth, subHeight), level + 1); children[2] = new QuadTree(new Rectangle(x, y + subHeight, subWidth, subHeight), level + 1); children[3] = new QuadTree(new Rectangle(x + subWidth, y + subHeight, subWidth, subHeight), level + 1); for (Point point : points) { for (QuadTree child : children) { if (child.insert(point)) { break; } } } points.clear(); } // 查询某个矩形内的点 public List<Point> query(Rectangle range) { List<Point> result = new ArrayList<>(); if (!boundary.intersects(range)) { return result; } for (Point point : points) { if (range.contains(point)) { result.add(point); } } if (children != null) { for (QuadTree child : children) { result.addAll(child.query(range)); } } return result; } } 2. 定义Point和Rectangle类 public class Point { public int x; public int y; public Point(int x, int y) { this.x = x; this.y = y; } } public class Rectangle { public int x; public int y; public int width; public int height; public Rectangle(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } public boolean contains(Point point) { return point.x >= x && point.x <= x + width && point.y >= y && point.y <= y + height; } public boolean intersects(Rectangle range) { return !(range.x > x + width || range.x + range.width < x || range.y > y + height || range.y + range.height < y); } } 3. 使用QuadTree进行空间索引 public class Main { public static void main(String[] args) { QuadTree quadTree = new QuadTree(new Rectangle(0, 0, 100, 100), 0); quadTree.insert(new Point(10, 10)); quadTree.insert(new Point(20, 20)); quadTree.insert(new Point(30, 30)); quadTree.insert(new Point(40, 40)); quadTree.insert(new Point(50, 50)); quadTree.insert(new Point(60, 60)); quadTree.insert(new Point(70, 70)); quadTree.insert(new Point(80, 80)); quadTree.insert(new Point(90, 90)); List<Point> points = quadTree.query(new Rectangle(25, 25, 50, 50)); System.out.println(points); } } 输出结果为:[Point{x=30, y=30}, Point{x=40, y=40}, Point{x=50, y=50}, Point{x=60, y=60}, Point{x=70, y=70}],表示查询到了在矩形(25, 25, 50, 50)内的所有点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值