經常使用來做空間劃分及近鄰搜索,是二叉空間劃分樹的一個特例。一般,對於維度爲k,數據點數爲N的數據集,kd樹適用於N≫2的k次方的情形。算法
假設在數據庫的表格T中存儲了學生的語文成績chinese、數學成績math、英語成績english,若是要查詢語文成績介於30~93分的學生,如何處理?假設學生數量爲N,若是順序查詢,則其時間複雜度爲O(N),當學生規模很大時,其效率顯然很低,若是使用平衡二叉樹,則其時間複雜度爲O(logN),能極大地提升查詢效率。平衡二叉樹示意圖爲:數據庫
對於1維數據的查詢,使用平衡二叉樹創建索引便可。若是如今將查詢條件變爲:語文成績介於30~93,數學成績結餘30~90,又該如何處理呢?性能
若是分別使用平衡二叉樹對語文成績和數學成績創建索引,則須要先在語文成績中查詢獲得集合S1,再在數學成績中查詢獲得集合S2,而後計算S1和S2的交集,若|S1|=m,|S2|=n,則其時間複雜度爲O(m*n),有沒有更好的辦法呢?優化
針對多維數據索引,是否也存在相似的一維的索引方法呢?先看2維數據的集合示意圖:spa
若是先根據語文成績,將全部人的成績分紅兩半,其中一半的語文成績<=c1,另外一半的語文成績>c1,分別獲得集合S1,S2;而後針對S1,根據數學成績分爲兩半,其中一半的數學成績<=m1,另外一半的數學成績>m1,分別獲得S3,S4,針對S2,根據數學成績分爲兩半,其中一半的數學成績<=m2,另外一半的數學成績>m2,分別獲得S5,S6;再根據語文成績分別對S3,S4,S5,S6繼續執行相似劃分獲得更小的集合,而後再在更小的集合上根據數學成績繼續,...blog
上面描述的就是構建KD樹的基本思路,其構建後的KD樹以下圖所示排序
如圖所示,l1左邊都是語文成績低於45分,l1右邊都是語文成績高於45分的;l2下方都是語文成績低於45分且數學成績低於50分的,l2上方都是語文成績低於45分且數學成績高於50分的,後面以此類推。下面的圖示,更清晰地表示了KD樹的結構及其對應的二叉樹:索引
a)切分維度選擇優化
構建開始前,對比數據點在各維度的分佈狀況,數據點在某一維度座標值的方差越大分佈越分散,方差越小分佈越集中。從方差大的維度開始切分能夠取得很好的切分效果及平衡性。
b)中值選擇優化
第一種,算法開始前,對原始數據點在全部維度進行一次排序,存儲下來,而後在後續的中值選擇中,無須每次都對其子集進行排序,提高了性能。
第二種,從原始數據點中隨機選擇固定數目的點,而後對其進行排序,每次從這些樣本點中取中值,來做爲分割超平面。該方式在實踐中被證實能夠取得很好性能及很好的平衡性。
本文采用常規的構建方式,以二維平面點(x,y)的集合(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)爲例結合下圖來講明k-d tree的構建過程。
a)構建根節點時,此時的切分維度爲x,如上點集合在x維從小到大排序爲(2,3),(4,7),(5,4),(7,2),(8,1),(9,6);其中值爲(7,2)。(注:2,4,5,7,8,9在數學中的中值爲(5 + 7)/2=6,但因該算法的中值需在點集合以內,因此本文中值計算用的是len(points)//2=3, points[3]=(7,2))
b)(2,3),(4,7),(5,4)掛在(7,2)節點的左子樹,(8,1),(9,6)掛在(7,2)節點的右子樹。
c)構建(7,2)節點的左子樹時,點集合(2,3),(4,7),(5,4)此時的切分維度爲y,中值爲(5,4)做爲分割平面,(2,3)掛在其左子樹,(4,7)掛在其右子樹。
d)構建(7,2)節點的右子樹時,點集合(8,1),(9,6)此時的切分維度也爲y,中值爲(9,6)做爲分割平面,(8,1)掛在其左子樹。至此k-d tree構建完成。數學