前言
在地图相关应用的开发中,我们常常遇到一个问题,当地图标注点过多的时候,会造成用户体验差、应用卡顿的情况。所以,我们需要一套高效的算法来解决标注的聚合、分散的逻辑。
先上代码:
https://github.com/indulgeIn/YBAnnotationViewSet
算法思想不局限于平台,如果你是Android开发者,大可浏览思路,然后看高德地图的示例C代码(链接在文底)。
分析
接下来一步步分析整体解决方案。
1、地图上标注显示逻辑
为了保证规律性和平均分配,采用区域划分方法显示标注。简单来说就是把屏幕分割成若干个区域,每个区域最多显示一个标注,然后根据地图缩放比例动态的设置这些区域的大小以达到最佳的用户体验。
2、为何要引入四叉树
如果有100条数据,我们可以嵌套循环找到合适的点放入相应的区域,循环10000次,如果有10000条数据,可能我们的操作系统就要抓狂了。这种计算方法是低效的,时间复杂度至少为O(n^2)。
所以,这里引入四叉树是必要的,它非常适合这个场景,看一张百度百科的图:
四叉树图解
我们将数据逐个放入这个树状结构(具体做法DEMO中有,本文只说思路),给每一个节点(可以想象成树干)一个范围,如图上所示。这个范围对于我们的需求来说是至关重要的。
3、如果从四叉树查找出需要的标注
首先,我们要理清一个逻辑,如果数据量很大,构建四叉树仍然需要一些时间,但是这个时间是我们允许的,相信你也不会频繁的请求大量标注数据。
关键问题就是在用户拖拽旋转结束的时候,我们需要调整我们界面的显示UI,也就是说,关键问题就是从这个四叉树里面查找出需要的标注,这部分的速度至关重要。
主要逻辑:
第一步:遍历屏幕划分的区域
第二步:比较该区域是否和四叉树元素范围有交集,无交集则舍弃,有交集继续向下查找
如此,时间复杂度被极大的降低。
优化:我对查找逻辑做了小优化。在第二步的时候,如果有交集,给是否继续向下查找做了一个开关。理由是,我们查找出所有在该划分区域内的标注,如果目的只是为了算出他们的平均中心点,就显得意义不大,大可查找出几个就停止查找。下面是大致的时间复杂度区别:(主要看‘查找标注次数’,执行效率在demo业务逻辑少的情况下看不出太大的区别而且浮动较大)
优化前
优化后
注意:由于地图是可以旋转视角和方向的,这两者变量决定了地图的处理需要格外的谨慎。地图的经纬度不能按照正常的坐标系来理解,通常采用经纬度范围来就行比对,所以进行经纬度复杂计算的时候不要企图全部转换为屏幕pt坐标系来计算。
如果有什么问题,欢迎留言咨询 _
格外说明:算法思路和C代码来着https://github.com/amap-demo/iOS-cluster-marker 这里只是用OC思维进行轻微重构,修改了部分逻辑,优化了部分代码,旨在帮助有刚需的同学更快的理解