KD Tree原理讲解

1.引子

在一张地图上,有600多个单位,每个单位之间都需要独立寻路,检测碰撞和寻找最近的敌方目标。当这一切需要在手机上流畅运行并尽可能快的在服务器进行模拟时,最简单的平方算法O(N^2)已经不能满足需求。


怎样减少计算的复杂度呢?


通过观察,可以发现,在地图左上角的单位根本无需和地图右下角的单位进行碰撞检测,因为它们离的太远了。


所以,通过对战场进行空间划分,可以避免大量的无效计算。


一种简单的划分方法是,将战场沿着横纵坐标划分为N * N的格子,只对在相同格子内的战斗单元做碰撞检测。


这种方法在大部分情况下简单有效,然而有以下几点问题:


1.当格子边长太大时,假设很多单位都聚集于一个或少数几个格子中,其实空间并没有有效划分


2.当格子边长太小时,一个格子内的单位可能太少了,也不能对空间进行有效划分

3.如果不查找附近的几个格子,可能或错过附近格子可能距离更近的单位


4.这种方法的空间复杂度是O(N2),在格子数很多的情况下,内存开销会很高

KD树k — dimensionaltree,也可称之为K维树,可以用更高的效率来对空间进行划分,并且其结构非常适合寻找最近邻居和碰撞检测。

2.KD Tree之前的树

1.四叉树


2.点四叉树 

在点上拆分而不是均匀划分空间

3.区域四叉树

通过区域的实分解来分割区域(树叶)

 3.KD Tree的原理

对于2维空间,KD树可称为2D树,因为空间只有两个坐标轴;对于3维空间,KD树可称为3D树,空间中有三个坐标轴;以此类推......


对于不同维度的空间,KD树的构建思路完全一致。下面以二维空间为例。


KD树的本质是一个二叉树,即一个根节点,划分为左子树和右子树。所以KD树的构建无非是两个问题:根节点的选择,左右子树的划分规则。


以下是KD树的构建过程:

  1. 选定一个轴,比如X轴,选择这个轴上的中位数的所在点为根节点
  2. 所有X比中位数X小的,都划分为左子树;反之,则划分为右子树
  3. 对于左右两个子树,重复第一步,但是需要把划分轴换成另外一个轴(Y)继续
  4. 重复以上过程,直到所有点都加入KD树中

以上图举例,第一步对X轴进行划分,点7,2的X坐标7为所有X坐标的中位数,其被确立为根节点;X坐标比7小的点5,4、2,3、4,7被划分到左子树;X坐标比7大的点9,6、8,1被划分到右子树。

对于左子树5,4、2,3、4,7,对它们的Y轴进行划分,点5,4的Y坐标4为所有左子树的Y坐标的中位数,其被确立为左子树的根节点;Y坐标比4小的点2,3被划分为左子树;Y坐标比4大的点4,7被划分为右子树。

对于右子树9,6、8,1,和左子树同理,也是对Y轴进行划分。

此时所有点都已经加入到KD树中,创建结束。

一个直观的理解是,创建方式看起来有点像对空间横纵切蛋糕的方式,对于2D空间,第一刀沿着X轴将空间划分为两半,第二刀又沿着Y轴分别将已经划分好的两半再划分为两半,第三刀又继续沿着X轴进行划分……直到所有点都落入KD树中 

另外一个例子:

4.数据结构与查询算法

1.如何定义其数据结构

构成:根的左右值,左右子树,以x还是y特征进行划分

 2.查询算法:

逻辑:

•如果节点在查询范围内,记录节点

•如果查询范围与左子树定义的区域相交,则查找它

•如果查询范围与左子树定义的区域相交,则查找它

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值