什么是四叉树?

四叉树(Quad Tree)是一种空间索引树,四叉树的每一个节点都代表着一块矩形区域。我们知道在平面直角坐标系中,平面可以被分为第一二三四象限,四叉树的每一个节点也类似,可以分裂为四个子节点,子节点在满足条件的情况下可以继续分裂,这样构成了一个四元的树状结构,就是四叉树。

四叉树的作用

通常使用树结构能够带来高效且简单的检索效果,四叉树也不例外,四叉树主要用于二维空间的检索(相应的,三维空间可以了解下八叉树,理论上来讲,对于N维空间的检索可以根据这个原理构成2^N叉树,此外多维空间的检索还有kd树)。

下面是用四叉树来存储某平面区域上许多小矩形的例子

其中这个区域被分为了许多个小矩形,每一个矩形都代表了一个四叉树的一个节点,最外层的大矩形就是四叉树的根节点(root),一些矩形被分割成了四个等大的小矩形,这是该节点的四个子节点,矩形越小,说明该节点的深度(depth)越大

四叉树的高效检索

下面是检索四叉树的某一矩形区域的例子

其中,与绿框无相交区域的节点不会被检索,这样一来可以大大减少检索量

(为什么有一些在绿框外的节点也会被检索到?这根存储方式有关,上面的实现是将落在分割线上的矩形存储在了父节点,这样只要检索区域与节点有相交,就要返回节点内所有的元素)

四叉树的操作

1、节点分裂

当满足特定条件时,为了获得更好的检索效率,四叉树的节点会发生分裂,分裂的做法是:以当前节点的矩形为中心, 划分出四个等大的矩形,作为四个子节点,每个节点深度=当前节点深度+1,根节点深度为0;并且将当前节点的元素重新插入到对应的子节点。

2、插入元素

1)平面的元素多种多样,点,线,图形,但都能够做一个统一,第一步都是要找出图形所覆盖的节点,这里以矩形为例

2)从根节点开始,如果当前节点无子节点,将元素插入到当前节点。如果存在子节点K,并且元素能够完全被子节K点所“包围”,就将元素插入到子节点K,对于子节点K进行上述递归操作;如果元素跨越了多个子节点,那就将元素存储在当前节点

3)如果某一节点元素超过特定值,并且深度小于四叉树允许的最大深度,分裂当前节点。

3、检索

1)对于给定检索区域,从根节点起,如果检索区域与当前节点有交集,返回当前节点的所有元素。

2)如果当前节点还有子节点,递归检索与检索区域有交集的子节点。

代码实现(Java)

public class QuadTree<T extends Rectangle> {private Node<T> root;public NormalQuadTree(Rectangle boundary) {this.root = new Node<>(boundary, 0);}public boolean insert(T t) {return root.insert(t);}public Set<T> retrieve(Rectangle retArea) {return root.retrieve(retArea);}private static class Node<T extends Rectangle> {static final int MAX_OBJECT_COUNT = 5;static final int MAX_DEEP = 4;static final int LEFT_TOP = 0;static final int LEFT_BOTTOM = 1;static final int RIGHT_TOP = 2;static final int RIGHT_BOTTOM = 3;private Rectangle boundary;private Set<T> objectSet;private List<Node<T>> childs = new ArrayList<>(4);private final int deep;Node(Rectangle boundary, int deep) {this.boundary = boundary;this.deep = deep;this.objectSet = new HashSet<>();}boolean insert(T t) {if (!t.intersects(this.boundary)) {return false;}if (!childs.isEmpty()) {int quadIndex = quadrantOf(t);if (quadIndex != -1) {return childs.get(quadIndex).insert(t);}}this.objectSet.add(t);if (this.childs.isEmpty()&& this.objectSet.size() > MAX_OBJECT_COUNT&& this.deep < MAX_DEEP) {this.split();}return true;}void split() {int hmid = this.boundary.x + this.boundary.width / 2;int vmid = this.boundary.y + this.boundary.height / 2;this.childs.add(LEFT_TOP, new Node<>(new Rectangle(boundary.x,boundary.y,boundary.width / 2,boundary.height / 2), deep + 1));this.childs.add(LEFT_BOTTOM, new Node<>(new Rectangle(boundary.x,vmid,boundary.width / 2,boundary.height / 2), deep + 1));this.childs.add(RIGHT_TOP, new Node<>(new Rectangle(hmid,boundary.y,boundary.width / 2,boundary.height / 2), deep + 1));this.childs.add(RIGHT_BOTTOM, new Node<>(new Rectangle(hmid,vmid,boundary.width / 2,boundary.height / 2), deep + 1));Set<T> temp = this.objectSet;this.objectSet = new HashSet<>();for (T t : temp) {insert(t);}}int quadrantOf(Rectangle rect) {int hmid = this.boundary.x + this.boundary.width / 2;int vmid = this.boundary.y + this.boundary.height / 2;int index = -1;if (rect.x + rect.width < hmid && rect.y + rect.height < vmid) {index = LEFT_TOP;} else if (rect.x + rect.width < hmid && rect.y > vmid) {index = LEFT_BOTTOM;} else if (rect.x > hmid && rect.y + rect.height < vmid) {index = RIGHT_TOP;} else if (rect.x > hmid && rect.y > vmid) {index = RIGHT_BOTTOM;}return index;}Set<T> retrieve(Rectangle retArea) {if (retArea.isEmpty()) {return new HashSet<>();}Set<T> resultSet = new HashSet<>(objectSet);if (!childs.isEmpty()) {int index = quadrantOf(retArea);if (index != -1) {return childs.get(index).retrieve(retArea);}for (Node<T> node : childs) {Rectangle inter = node.boundary.intersection(retArea);if (!inter.isEmpty()) {resultSet.addAll(node.retrieve(inter));}}}return resultSet;}}
}

四叉树的应用

游戏开发中经常有碰撞检测的算法,对于平面上N个图形,如果需要检测互相之间是否发生碰撞,最基本的做法是进行N(N-1)次比较,时间复杂度是O(n^2),n较小时能够接受,当n>10000时效率可能就会明显降低了,如果四叉树使用合理,可以将复杂度降到O(nlog n),可以说是个很大的改进。

四叉树的优化

1、有人会发现这个四叉树没有删除算法,因为游戏开发中遇到的平面图形常常是频繁移动的(都静态的话就用不着相互之间碰撞检测了),这就意味着每一帧都要重建四叉树,这样就自然地避免了删除特定节点。但是也应该能想到大致优化的方案了吧,只修改移动后所在覆盖节点发生变化的元素,将其删除再插入。四叉树如果要实现删除首先也得检索删除元素所在节点,删除结束后,考虑到空间占用,可能要进行子节点的合并。

2、来看下面这棵四叉树

由于元素分布均匀,导致四叉树变成了一个看起来近似网格的结构

在一维元素中,满二叉树可以用一维数组存储

类似的,四叉树在元素均匀分布的条件下可以用二维数组存储

这样做的好处是

1)检索更快

检索四叉树的某个元素所在的节点需要O(log n)的复杂度,而二维数组只需要O(1),很简单,就是计算一下所坐标,转换成二维数组的下标

2)维护更加简便

二维数组的方式避免了递归操作

空间索引-四叉树的实现及其应用相关推荐

  1. geotools应用-JTS生产四叉树索引和R树索引

    微信搜索:"二十同学" 公众号,欢迎关注一条不一样的成长之路 geotools介绍 geotools官网https://geotools.org/ Geotools是一个java类 ...

  2. 优化巨量关键词的匹配(转载笔记)

    优化巨量关键词的匹配(转载笔记) 问题由来 前些天工作中遇到一个问题: 有 60万 条短消息记录日志,每条约 50 字,5万 关键词,长度 2-8 字,绝大部分为中文.要求将这 60万 条记录中包含的 ...

  3. 希尔伯特曲线的绘制c语言,用四叉树和希尔伯特曲线做空间索引

    <用四叉树和希尔伯特曲线做空间索引>由会员分享,可在线阅读,更多相关<用四叉树和希尔伯特曲线做空间索引(11页珍藏版)>请在人人文库网上搜索. 1.超酷算法:用四叉树和希尔伯特 ...

  4. 地理空间索引实现:z 曲线、希尔伯特曲线、四叉树, 最邻近几何特征查询、范围查询

    我的GIS/CS学习笔记:https://github.com/yunwei37/ZJU-CS-GIS-ClassNotes <一个浙江大学本科生的计算机.地理信息科学知识库 > 详细代码 ...

  5. 超酷算法:用四叉树和希尔伯特曲线做空间索引

    原文出处:http://blog.jobbole.com/81106/ 随着越来越多的数据和应用和地理空间相关,空间索引变得愈加重要.然而,有效地查询地理空间数据是相当大的挑战,因为数据是二维的(有时 ...

  6. 四叉树和希尔伯特曲线做空间索引

    前序 四叉树或四元树也被称为Q树(Q-Tree).四叉树广泛应用于图像处理.空间数据索引.2D中的快速碰撞检测.存储稀疏数据等,而八叉树(Octree)主要应用于3D图形处理.对游戏编程,这会很有用. ...

  7. GIS空间索引(2)--格网索引与四叉树索引

    在介绍空间索引之前,先谈谈什么叫"索引".对一个数据集做"索引",是为了提高对这个数据集检索的效率.书的"目录"就是这本书内容的" ...

  8. 网格与四叉树空间索引

    在介绍空间索引之前,先谈谈什么叫"索引".对一个数据集做"索引",是为了提高对这个数据集检索的效率.书的"目录"就是这本书内容的" ...

  9. 空间索引 - GeoHash算法及其实现优化

    转自原文 空间索引 - GeoHash算法及其实现优化 上篇博客中提到了空间索引的用途和多种数据库对空间索引的支持情况,那么在应用层以下,好学的小伙伴应该会考虑空间索引的实现原理了. 目前空间索引的实 ...

  10. JUST技术:空间连接运算与空间索引

    一.空间连接定义 随着全球定位系统和移动互联设备的普及,海量的空间数据也随之产生.空间连接(Spatial Join)运算是一类最常用的空间数据分析算子,具有广泛的应用场景.例如统计地铁站周围500米 ...

最新文章

  1. linux下出现重定义,Oracle Online Redefinition在线重定义
  2. 做一个计算器_2019年初级会计考试考生能不能带计算器?现在统一回复!
  3. android签名的应用-- 禁止未经授权签名的apk安装
  4. python怎么打不开图片_为什么pygame打不开图片 各种格式的都试过了
  5. 为什么ui框架设计成单线程_评估UI设计的备忘单
  6. server sql 去 反斜杠_%00截断配合反序列化的奇妙利用
  7. win7查看电脑ip地址的方法
  8. Python个 flask 教程地址 做个记录方便以后学习用
  9. Qt5及模块架构分析
  10. python自学行吗-有编程基础Python自学行吗?
  11. 如何断点调试Tomcat源码
  12. 计算机科学现代教育,现代教育技术教程-计算机科学教育.pdf
  13. 【16年浙江省赛 B ZOJ 3937】More Health Points【树上dfs、斜率优化dp、动态维护下凸壳】
  14. pli测试50题题库_人才测评题库60题测试(附答案).doc
  15. inode磁盘满了清理
  16. 八数码(有一个空的移动拼图模型+map.count的用法)
  17. JAVA教材(推荐新手学习)
  18. 双显示器如何设置上下显示和鼠标上下进入第二屏幕?
  19. 前端页面----昵图网(简单版)
  20. Java递归解决老鼠走迷宫问题

热门文章

  1. Python词频统计(去重)
  2. 《社会调查数据管理——基于Stata 14管理CGSS数据》一3.4 Stata的一些术语及使用通则...
  3. Zmodem协议工作原理
  4. 学习PLC要学哪些知识?
  5. 小米盒子共享电脑文件 服务器,小米盒子3S访问局域网电脑共享安装软件和观看视频的方法...
  6. [面经]星环科技大数据后台开发实习面试
  7. Dbgview调试工具的使用
  8. WIFI抓包实战篇——使用Kali 同时抓取多个智能家居数据包
  9. oracle密码已过期问题解决
  10. 双霖度盘下载器(第三方百度网盘不限速下载工具)