kd樹(k-dimensional樹的簡稱),是一種分割k維數據空間的數據結構,主要應用於多維空間關鍵數據的近鄰查找(Nearest Neighbor)和近似最近鄰查找(Approximate Nearest Neighbor)。node
其實KDTree就是二叉查找樹(Binary Search Tree,BST)的變種。二叉查找樹的性質以下:
1)若它的左子樹不爲空,則左子樹上全部結點的值均小於它的根結點的值;
2)若它的右子樹不爲空,則右子樹上全部結點的值均大於它的根結點的值;
3)它的左、右子樹也分別爲二叉排序樹;
例如:
算法
若是咱們要處理的對象集合是一個K維空間中的數據集,咱們首先須要肯定是:怎樣將一個K維數據劃分到左子樹或右子樹?數組
在構造1維BST樹相似,只不過對於Kd樹,在當前節點的比較並非經過對K維數據進行總體的比較,而是選擇某一個維度d,而後比較兩個K維數據在該維度 d上的大小關係,即每次選擇一個維度d來對K維數據進行劃分,至關於用一個垂直於該維度d的超平面將K維數據空間一分爲二,平面一邊的全部K維數據 在d維度上的值小於平面另外一邊的全部K維數據對應維度上的值。也就是說,咱們每選擇一個維度進行如上的劃分,就會將K維數據空間劃分爲兩個部分,若是我 們繼續分別對這兩個子K維空間進行如上的劃分,又會獲得新的子空間,對新的子空間又繼續劃分,重複以上過程直到每一個子空間都不能再劃分爲止。以上就是構造 Kd-Tree的過程,上述過程當中涉及到兩個重要的問題:數據結構
一、在哪一個維度上進行劃分?
一種選取軸點的策略是median of the most spread dimension pivoting strategy,統計樣本在每一個維度上的數據方差,挑選出對應方差最大值的那個維度。數據方差大說明沿該座標軸方向上數據點分散的比較開。這個方向上,進行數據分割能夠得到最好的平衡。
二、怎樣確保創建的樹儘可能地平衡?
給定一個數組,怎樣才能獲得兩個子數組,這兩個數組包含的元素 個數差很少且其中一個子數組中的元素值都小於另外一個子數組呢?方法很簡單,找到數組中的中值(即中位數,median),而後將數組中全部元素與中值進行 比較,就能夠獲得上述兩個子數組。一樣,在維度d上進行劃分時,劃分點(pivot)就選擇該維度d上全部數據的中值,這樣獲得的兩個子集合數據個數就基本相同了。3d
1)、在K維數據集合中選擇具備最大方差的維度k,而後在該維度上選擇中值m爲pivot對該數據集合進行劃分,獲得兩個子集合;同時建立一個樹結點node,用於存儲;
2)、對兩個子集合重複(1)步驟的過程,直至全部子集合都不能再劃分爲止;rest
舉個例子:
假設有6個二維數據點{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},數據點位於二維空間內(以下圖中黑點所示)。kd樹算法就是要肯定圖1中這些分割空間的分割線(多維空間即爲分割平面,通常爲超平面)。下面就要經過一步步展現kd樹是如何肯定這些分割線的。
對象
例1:查找點Q(2.1,3.1)
以下圖所示,紅色的點即爲要查找的點。經過圖4二叉搜索,順着搜索路徑很快就能找到當前的最鄰近點(2,3)。
在上述搜索過程當中,產生的搜索路徑節點有<(7,2),(5,4),(2,3)>。爲了找到真正的最近鄰,還須要進行'回溯'操做,首先以(2,3)做爲當前最近鄰點nearest,計算其到查詢點Q(2.1,3.1)的距離dis爲0.1414,而後回溯到其父節點(5,4),並判斷在該父節點的其餘子節點空間中是否有距離查詢點Q更近的數據點。以(2.1,3.1)爲圓心,以0.1414爲半徑畫圓,如圖6所示。發現該圓並不和超平面y = 4交割,即這裏:|Q(k) - m|=|3.1 - 4|=0.9 > 0.1414,所以不用進入(5,4)節點右子空間中去搜索。
再回溯到(7,2),以(2.1,3.1)爲圓心,以0.1414爲半徑的圓更不會與x = 7超平面交割,所以不用進入(7,2)右子空間進行查找。至此,搜索路徑中的節點已經所有回溯完,結束整個搜索,返回最近鄰點(2,3),最近距離爲0.1414。blog
例2:查找點Q(2,4.5)
以下圖所示,一樣通過圖4的二叉搜索,可得當前的最鄰近點(4,7),產生的搜索路徑節點有<(7,2),(5,4),(4,7)>。首先以(4,7)做爲當前最近鄰點nearest,計算其到查詢點Q(2,4.5)的距離dis爲3.202,而後回溯到其父節點(5,4),並判斷在該父節點的其餘子節點空間中是否有距離查詢點Q更近的數據點。以(2,4.5)爲圓心,覺得3.202爲半徑畫圓,如圖7所示。發現該圓和超平面y = 4交割,即這裏:|Q(k) - m|=|4.5 - 4|=0.5 < 3.202,所以進入(5,4)節點右子空間中去搜索。因此,將(2,3)加入到搜索路徑中,如今搜索路徑節點有<(7,2), (2, 3)>。同時,注意:點Q(2,4.5)與父節點(5,4)的距離也要考慮,因爲這兩點間的距離3.04 < 3.202,因此將(5,4)賦給nearest,而且dist=3.04。
接下來,回溯至(2,3)葉子節點,點Q(2,4.5)和(2,3)的距離爲1.5,比距離(5,4)要近,因此最近鄰點nearest更新爲(2,3),最近距離dis更新爲1.5。回溯至(7,2),如圖8所示,以(2,4.5)爲圓心1.5爲半徑做圓,並不和x = 7分割超平面交割,即這裏:|Q(k) - m|=|2 - 7|=5 > 1.5。至此,搜索路徑回溯完。返回最近鄰點(2,3),最近距離1.5。
排序
Kd樹在維度較小時(好比20、30),算法的查找效率很高,然而當數據維度增大(例如:K≥100),查找效率會隨着維度的增長而迅速降低。假設數據集的維數爲D,通常來講要求數據的規模N知足N>>2的D次方,才能達到高效的搜索。遞歸
爲了可以讓Kd樹知足對高維數據的索引,Jeffrey S. Beis和David G. Lowe提出了一種改進算法——Kd-tree with BBF(Best Bin First),該算法可以實現近似K近鄰的快速搜索,在保證必定查找精度的前提下使得查找速度較快。