學習筆記 kd tree

2021-07-25 19:23:40 字數 2852 閱讀 1606

kd-tree用來維護n維空間中的點的一種資料結構。

支援插入、刪除、查詢k臨近(包括最遠點對和最近點對)。

kd-tree本質是一顆二叉樹。

每一層選擇乙個維度,找到當前維度的中點(讓樹盡量平衡),經過這個點,在當前維度切割,分成左右兩個子樹。

通常維度的選擇是順次迴圈的,較易實現。

更優的方法是找到方差最大的維度劃分。

kd-tree的每乙個節點可以理解為是維護乙個n維立方體。

i.e.一維是一條線段,二維是乙個矩形,三維就是乙個長方體。

實際上我們就是這樣實現的。

節點中需要維護:

劃分點的座標

每乙個維度的座標範圍

孩子的指標

類似於平衡樹的構建方式。

靈活運用stl函式nth_element找到當前維度的中點。

遞迴建樹。

構建複雜度o(

nlog

n)還是遞迴查詢。

到達乙個節點首先更新答案。

然後判斷進入哪個子樹繼續查詢。

怎麼判斷呢?

求一下兩個子樹可能的最優取值,走那個較優的子樹。

具體來說,比如你要求平面上的最遠點,你就找詢問座標和兩個子樹所表示的矩形的最遠距離,先走距離較大的那個。

如果最優的值都比當前答案優了,我們就可以不去遞迴了。

為什麼上面說先走呢?

因為另一棵子樹中仍可能有點更新答案,所以還需遞迴另一棵子樹。

感覺很暴力對不對……

就是暴力優化= =

複雜度被證明最壞是o(

n√) 的。

但是我還沒有找到什麼地方有詳細的證明。

一脈相承。

插入乙個點,判斷當前維度應該被分到左子樹還是右子樹。

遞迴進行,發現不能遞迴下去了,就插在那個位置。

複雜度o(l

ogn)

替罪羊樹式刪除。

找到那個點,打乙個刪除標記,如果一棵子樹中的刪除標記佔了樹的大小的一半就重構它。

複雜度o(l

ogn)

我們發現kd-tree並沒有像平衡樹那樣的維護平衡的操作!

插入和刪除的次數多了,可能會發現我們樹的形態極其扭曲,影響我們各種操作的複雜度。

有兩種方法來維護樹的平衡,都是重構的思想。

暴力重構:我們可以每隔一定次數插入刪除操作,就將整棵樹暴力重構,強行變成一顆二叉樹。均值不等式搞一下好像是nl

ogn−

−−−−

√ 是最優的?複雜度會比原來稍微高一點。

替罪羊樹式重構:利用替罪羊樹的思想。找到乙個平衡因子α∈

[0.5,1

] 如果某一棵子樹的大小佔當前樹的大小比例超過

α ,就暴力重構這個子樹,強行變成二叉樹。這樣維護的複雜度證明是o(

nlog

n)的。因為我還不會替罪羊樹,所以先坑著

[cqoi2016]k遠點對

維護乙個大小為2k的小根堆。

每次更新答案如果答案大於堆頂,就彈出堆頂插入當前答案。

最後堆頂就是答案。

指標版+記憶體池

距離的計算方式可以替換:曼哈頓距離,歐式距離,切比雪夫距離……

#include

#include

using namespace std;

#define inf 0x3f3f3f3f

#define n 1000010

#define lim 80000//重構引數

int cur;//排序的維

int n,m,x,y,opt;

struct point;

point(int x,int y)

bool

operator

< (const point &n1) const

int get_mn(const point &n1)//到矩形的最短距離

return ret;

}int get_dis(const point &n1)//到點的最短距離

node();

void pushup();//更新點的範圍

}*null;

node::node()

void node::pushup()

if (rch!=null)}}

node pool[n];

int poolt;

node *root;

point t;

int ans,cnt;

node *newnode()

node *build(int l,int r,int dim)//建樹,[l,r],維度

void init()

void query_mn(node *node)//最近點查詢

else

}int solve_mn(point n1)//注意初始化的資訊

void insert(node *node,int dim)//插入

else

if (node->rch!=null)

insert(node->rch,dim^1);

else

node->pushup();

}void solve_insert(point n1)//cnt是計數器

else

}}

k臨近查詢

priority_queuelong,vector

long>,greaterlong> > q;

namespace kdtree

else

}...

}int main()

KD tree學習筆記

如上圖 a 我們先對待識別的物體的影象進行sift特徵點的檢測和特徵點的描述,然後得到了sift特徵點集合。接下來生成物體目標描述要做的就是對特徵點集合進行資料組織,形成一種特殊的表示,其作用是為了加速特徵點匹配的過程。所謂的特徵點匹配本質上是乙個通過距離函式 例如歐式距離 在高維向量之間進行相似性...

KD Tree學習筆記

kdtree是一種用於分割k維資料空間的資料結構,主要應用於多維空間關鍵資料的搜尋。例如 範圍搜尋和最近鄰搜尋 kdtree的每個節點表示k維空間的乙個點 每次空間劃分按照輪轉法劃分,即如果這次選擇了在第i維上劃分,則下一次就在 i 1 k上劃分 int id,n,k,c struct p p ma...

K D Tree 學習筆記

又是乙個不需要證明的東西,複雜度基本玄學。具體來說 k d tree 是解決高維問題的乙個資料結構 其實一般是二維 k d tree 本質上是一棵二叉搜尋樹,其的基本思想就是遍歷整個狀態空間加剪枝。設問題維度是k,其單次查詢的複雜度大概是 o n 我們一般採用每次隨機找乙個維度,以這個維度排序,且以...