3.5 二叉查找树的几何应用
一.一维范围查找
1.希望增加2个功能:range count和range search。
range count:lo和hi之间有多少个键。
range search:lo和hi之间有哪些键。
2.范围计数:利用二叉查找树的rank()方法,可以找到小于某个键的数量。如果最大界在二叉查找树中,需要+1,不在则直接rank(hi)-rank(lo)即可。
(1)代码实现:(更多代码见3.2二叉查找树)
/** * 判断某个key是否存在的方法,和查找相同 */ //比Node大,去右边找,比Node小去左边找 public boolean contains(Key key) { Node x=root; while(x!=null) { int cmp = key.compareTo(x.key); if (cmp<0) x=x.left; else if(cmp>0) x=x.right; else return true; } return false; } /** * 实现一维范围计数,包括两个端点的个数 */ public int rangeCount(Key lo,Key hi) { if(contains(hi)) return rank(hi)-rank(lo)+1; else return rank(hi)-rank(lo); }
(2)运行时间lgN
3.范围查找思路:运行时间C+lgN(C代表lo和hi之间的键的个数)
(1)递归找到左子树的所有键(只要有任意一个键可能在范围中)
(2)键值当前结点的键
(3)递归找到右子树的所有键(只要有任意一个键可能在范围中)
二.线段的交点
1.目标:给定N个垂直和水平的线段,找出所有的交点。
2.sweep-line algorithm扫描线算法
使用一个垂直线从左至右扫描
(1)如果到达线段的左边,将它的纵坐标当做key插入到二叉树中,如果到达该线段的右边,,则从二叉树中删除该key
(2)如果扫描到一个垂直线,则根据起始和终止的y值,做一个一维范围查找计数,计数的个数就表示交点的个数。
3.该算法的性能是NlogN+R。(表示在N个线段中找到R个相交点)
4.该算法将一个二维的线段相交问题转为为了一个一维范围查找的问题。
三.k-d树
1.二维范围搜索。包括如何插入一个二维的key,如何查找一个二维的key,如何在一个二维范围内(两个二维点确定的一个矩形)找到所有的key(range search),以及共有多少个key(range count)
2.一个思路:网格实现
(1)将空间划分为M*M的区域,用一个二维数组表示每一个区域,对于每一个区域维持一个列表list
(2)插入:将点(x,y)放在对应的小区域中,并插入到该区域维持的列表中
(3)区间查找:只需要检查区间(矩形)占据的那几个小区域的列表即可。
3.对于网格实现的范围查询来说,有一个space-time tradeoff。
(1)需要的空间为M2+N,需要的时间为平均每个小区域需要检查1+N/M2个点
(2)M过大,需要的空间大。M过小,每一个小区域需要的时间长
(3)M最好取√N,此时如果点是随机分布,那么初始化数据需要N,插入点需要1,范围搜索每个点需要1
(4)可见,在点最终随机分布(evenly-distributed)时,这是一种很快且简单的方法。但是在实际中,点的分布往往具有簇的特性(而且这种情况也很常见),即分布在相近的位置,会造成链表过长,大大增加查找时间。(类似基于拉链的散列表)
4.为了解决上述问题,可以使用空间划分树,例如2d树。
5.2d树的实现。一种特殊的BST,使用x和y坐标作为键。递归的将2维空间划分为2部分。
(1)插入:从0层开始,偶数层使用|来划分平面为2个部分,左边的点放在左子树里,右边的点放在右子树里。奇数层使用---,下面的点放在左子树,上面的点放在右子树里。
(2)范围查找
①检查结点是否在给定的矩形中(从根节点开始)
②递归的检测左/下(只要有一个点在矩形中)
③递归的检测右/上(只要有一个点在矩形中)
(3)一般来说,时间是R+logN。假设是平衡树,最坏的情况是R+√N。
6.2d树的其他应用
(1)目标:找到指定点的最近邻点
(2)算法:(不是很理解如何去除某些分支的??)
①计算结点到指定点的距离(从根节点开始)
②递归的查询左/下(如果可能包含一个更近的点)
③递归的查询右上(如果可能包含一个更近的点)
(3)一般来说,性能是logN,最坏的情况N
7.k-d树。递归的将k维空间划分为2部分。
四.一维区间搜索
1.目标:数据结构变为了区间的集合,希望能够完成区间的插入,区间的删除,查询区间,以及区间交叉查询。
2.区间查找树。一个特殊的二叉查找树,每个结点存储区间(lo,hi),存储该结点的子树的最大端点值,并且使用左端点作为BST的键。
3.插入。区间(lo,hi)
(1)使用lo作为键,插入到BST中
(2)更新搜索路径上每个结点的最大值。
4.查找。找到任意一个区间可以和区间(lo,hi)相交即可
(1)如果结点的区间和查询区间相交,即返回
(2)如果左子树是空,去右边
(3)如果左子树的最大端点小于lo,去右边
(4)上面不满足,则取左边
五.矩形相交
1.目标:找出N个直交的矩形之间所有的交点(只有垂直和水平的矩形)
2.sweep-line算法的变型,多了一维区间搜索。
使用一个垂直线从左至右扫描
(1)如果到达矩形的左边,将它的纵坐标区间(lo,hi)当做key插入到二叉树中,如果到达该矩形的右边,,则从二叉树中删除该key
(2)如果扫描到另一个矩形,则根据起始和终止的y值,做一个一维区间搜索。
3.时间NlogN+RlogN