KD-tree的建立與遍歷
阿新 • • 發佈:2018-12-31
(來源於百度百科)
一、構建演算法
k-d樹是一個二叉樹,每個節點表示一個空間範圍。表1給出的是k-d樹每個節點中主要包含的資料結構。 表1 k-d樹中每個節點的資料型別域名 | 資料型別 | 描述 |
Node-data | 資料向量 | 資料集中某個資料點,是n維向量(這裡也就是k維) |
Range | 空間向量 | 該節點所代表的空間範圍 |
split | 整數 | 垂直於分割超平面的方向軸序號 |
Left | k-d樹 | 由位於該節點分割超平面左子空間內所有資料點所構成的k-d樹 |
Right | k-d樹 | 由位於該節點分割超平面右子空間內所有資料點所構成的k-d樹 |
parent | k-d樹 | 父節點 |
演算法:構建k-d樹(createKDTree) |
輸入:資料點集Data-set和其所在的空間Range |
輸出:Kd,型別為k-d tree |
1.If Data-set為空,則返回空的k-d tree |
2.呼叫節點生成程式: (1)確定split域:對於所有描述子資料(特徵向量),統計它們在每個維上的資料方差。以SURF特徵為例,描述子為64維,可計算64個方差。挑選出最大值,對應的維就是split域的值。資料方差大表明沿該座標軸方向上的資料分散得比較開,在這個方向上進行資料分割有較好的解析度; (2)確定Node-data域:資料點集Data-set按其第split域的值排序。位於正中間的那個資料點被選為Node-data。此時新的Data-set' = Data-set\Node-data(除去其中Node-data這一點)。 |
3.dataleft = {d屬於Data-set' && d[split] ≤ Node-data[split]} Left_Range = {Range && dataleft} dataright = {d屬於Data-set' && d[split] > Node-data[split]} Right_Range = {Range && dataright} |
4.left = 由(dataleft,Left_Range)建立的k-d tree,即遞迴呼叫createKDTree(dataleft,Left_ Range)。並設定left的parent域為Kd; right = 由(dataright,Right_Range)建立的k-d tree,即呼叫createKDTree(dataright,Right_ Range)。並設定right的parent域為Kd。 |
- 從root節點開始,DFS搜尋直到葉子節點,同時在stack中順序儲存已經訪問的節點。
- 如果搜尋到葉子節點,當前的葉子節點被設為最近鄰節點。
- 然後通過stack回溯: 如果當前點的距離比最近鄰點距離近,更新最近鄰節點. 然後檢查以最近距離為半徑的圓是否和父節點的超平面相交. 如果相交,則必須到父節點的另外一側,用同樣的DFS搜尋法,開始檢查最近鄰節點。 如果不相交,則繼續往上回溯,而父節點的另一側子節點都被淘汰,不再考慮的範圍中.
- 當搜尋回到root節點時,搜尋完成,得到最近鄰節點。