以前用B-K tree做过一个题,最近学习k-d tree,感觉这两个树有某些相似,这个俩种树都是寻找距目标点临近最近的点(B-K tree针对给定距离k以内,k-d tree针对给定最近的k个点)。
其中B-K tree只要求数据点之间定义可度量的距离,支持求距给定点距离k以内的数据点。相对于暴力法来说,是常数级别的提高,但有时会很有效(比如数据点之间距离范围很大,但阀值k很小),一个应用就是实现单词纠错程序。当距离范围较大时,还可以采用分段映射来实现。
k-d tree除了要求数据点之间定义可度量距离外,还要求数据点用向量来描述(因为要按照不同维度进行划分)。建树时间复杂度为O(K*nlgn),插入和删除都为O(K*logn),查询k临近为O(K*lgk*T),其中T为一次查询访问点数量,T最差为O(n^(1-1/k))。维数较高时,效率明显下降,所以又有了BBF优化,大概就是把存储路径上节点的堆栈换成优先队列,按照点距区域距离最短优先的回溯并更新最近点,当队列为空或者当前最近点距离小于对队首权重时即为答案。如果不要求解的最优性,可以通过提前返回的方式以更高的效率得到较优解。
在不考虑效率的情况下,B-K tree可以通过倍增二分的方法实现k-d tree的功能,如果数据点用向量描述,k-d tree也可以实现B-K tree的功能。
附上一道测试题目,二维曼哈顿距离,注释掉的代码为bbf优化,效率只提升了一点,看来bbf优化要在较高维度才有显著效果。
http://www.lydsy.com/JudgeOnline/problem.php?id=2648
<span style="font-size:14px;">#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <utility>
#include <cstring>
#include <map>
#include <climits>
#include <queue>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned UI;
const int MAXN(500010);
const int MAXK(100010);
const int MAXL(10);
const int MAXC(2);
const int INF((INT_MAX-1)/2);
const int F(0);
template<typename T>
inline bool checkmax(T &a, const T &b){
return b > a? ((a = b), true): false;
}
template<typename T>
inline bool checkmin(T &a, const T &b){
return b < a? ((a = b), true): false;
}
template<typename T>
inline T ABS(T a){
return a < 0? -a: a;
}
struct PO{
int co[MAXC];
friend bool operator < (const PO &a, const PO &b){
for(int i = 0; i < MAXC; ++i)
if(a.co[i] != b.co[i])
return a.co[i] < b.co[i];
return false;
}
friend bool operator == (const PO &a, const