首页 > 代码库 > kd tree学习 (最近邻域查询)

kd tree学习 (最近邻域查询)

https://zhuanlan.zhihu.com/p/22557068

http://blog.csdn.net/zhjchengfeng5/article/details/7855241

 

KD树在算法竞赛中主要用来做各种各样的平面区域查询,包含则累加直接返回,相交则继续递归,相离的没有任何贡献也直接返回。可以处理圆,三角形,矩形等判断起来相对容易的平面区域内的符合加法性质的操作。

比如查询平面内欧几里得距离最近的点的距离。

kdtree其实有点像搜索,暴力+剪枝。

每次从根结点向下搜索,并进行剪枝操作,判断是否有必要继续搜索。

它是通过横一刀,竖一刀,横一刀再竖一刀将平面进行分割,建立二叉树。

建树的复杂度是O(nlogn), 每次用nth_element()在线性时间内取出中位数。 T(n) = 2T(n/2) + O(n) = O(nlogn)

查询复杂度呢? 据第二个链接的博客说最坏是O( sqrt(n) ) 的。并不会分析查询复杂度。

 

HDU2966 裸kdtree

题意:给平面图上N(≤ 100000)个点,对每个点,找到其他 欧几里德距离 离他最近的点,输出他们之间的距离。保证没有重点。

 

技术分享
 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 #define N 200010
 5 const ll inf = 1e18;
 6 int n,i,id[N],root,cmp_d;
 7 int x, y;
 8 struct node{int d[2],l,r,Max[2],Min[2],val,sum,f;}t[N];
 9 bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
10 void umax(int&a,int b){if(a<b)a=b;}
11 void umin(int&a,int b){if(a>b)a=b;}
12 void up(int x){
13     if(t[x].l){
14         umax(t[x].Max[0],t[t[x].l].Max[0]);
15         umin(t[x].Min[0],t[t[x].l].Min[0]);
16         umax(t[x].Max[1],t[t[x].l].Max[1]);
17         umin(t[x].Min[1],t[t[x].l].Min[1]);
18     }
19     if(t[x].r){
20         umax(t[x].Max[0],t[t[x].r].Max[0]);
21         umin(t[x].Min[0],t[t[x].r].Min[0]);
22         umax(t[x].Max[1],t[t[x].r].Max[1]);
23         umin(t[x].Min[1],t[t[x].r].Min[1]);
24     }
25 }
26 int build(int l,int r,int D,int f){
27     int mid=(l+r)>>1;
28     cmp_d=D,std::nth_element(t+l,t+mid,t+r+1,cmp);
29     id[t[mid].f]=mid;
30     t[mid].f=f;
31     t[mid].Max[0]=t[mid].Min[0]=t[mid].d[0];
32     t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1];
33     //t[mid].val=t[mid].sum=0;
34     if(l!=mid)t[mid].l=build(l,mid-1,!D,mid);else t[mid].l=0;
35     if(r!=mid)t[mid].r=build(mid+1,r,!D,mid);else t[mid].r=0;
36     return up(mid),mid;
37 }
38 
39 ll dis(ll x1, ll y1, ll x, ll y) {
40     ll xx = x1-x, yy = y1-y;
41     return xx*xx+yy*yy;
42 }
43 ll dis(int p, ll x, ll y){//估价函数, 以p为子树的最小距离
44     ll xx = 0, yy = 0;
45     if(t[p].Max[0] < x) xx = x-t[p].Max[0];
46     if(t[p].Min[0] > x) xx = t[p].Min[0]-x;
47     if(t[p].Max[1] < y) yy = y-t[p].Max[1];
48     if(t[p].Min[1] > y) yy = t[p].Min[1]-y;
49     return xx*xx+yy*yy;
50 }
51 ll ans;
52 void query(int p){
53     ll dl = inf, dr = inf, d = dis(t[p].d[0], t[p].d[1], x, y);
54     if(d) ans = min(ans, d);
55 
56     if(t[p].l) dl = dis(t[p].l, x, y);
57     if(t[p].r) dr = dis(t[p].r, x, y);
58     if(dl < dr){
59         if(dl < ans) query(t[p].l);
60         if(dr < ans) query(t[p].r);
61     }
62     else {
63         if(dr < ans) query(t[p].r);
64         if(dl < ans) query(t[p].l);
65     }
66 }
67 
68 int main(){
69     int T; scanf("%d", &T);
70     while(T--){
71         scanf("%d", &n);
72         for(int i = 1; i <= n; i++){
73             scanf("%d%d", &t[i].d[0], &t[i].d[1]);
74             t[i].f = i;
75         }
76         int rt = build(1, n, 0, 0);
77         for(int i = 1; i <= n; i++){
78             ans = inf;
79             x = t[ id[i] ].d[0], y = t[ id[i] ].d[1];
80             query(rt);
81             printf("%lld\n", ans);
82         }
83     }
84     return 0;
85 }
View Code

 

kd tree学习 (最近邻域查询)