kd樹本質上是一種二叉樹,它擁有具備特定排列順序的**節點以便查詢資料,即在二叉排序樹之中,某個**節點左子樹的值均小於**節點的值,而右側均大於**節點的值,如果用中序遍歷這棵樹,它的列印順序將是從小到大遞增的順序。當然剩下的科普就不說了,這也是在pcl庫當中,最常用的輪子之一,處理點雲速度非常快。另外,knn演算法是機器學習訓練的一種非常有效的分類方法,手擼這個演算法就顯得很重要了。當然,在企業級應用中,還是用別人的輪子吧~
首先是資料與樹節點的結構體,在樹節點中,具備資料、**維與左右孩子:
struct data
;struct tnode
;
接下來是判斷每次**時的**維度,在這裡只選擇二維平面上的兩個方向進行比較:
bool comparex(struct data a, struct data b)
bool comparey(struct data a, struct data b)
bool equal(struct data a, struct data b)
else }
//在每次決定樹的**節點時,為了枝的分散效果需比較xy維度的方差,取大者為**依據
void choosesplit(std::vectorpointsdata, int size, int &split, struct data &splitchoice)
float v1 = temp1 - temp2 * temp2;
temp1 = temp2 = 0;
//計算y方向上的方差
for (int j = 0;j < size;++j)
float v2 = temp1 - temp2 * temp2;
//取大者為**維
split = v1 > v2 ? 0:1;
struct data tempx, tempy;
if(0 == split)
else
//給**節點賦值
splitchoice.i = pointsdata[size/2].i;
splitchoice.x = pointsdata[size/2].x;
splitchoice.y = pointsdata[size/2].y;
}
接下來是遞迴建立kd樹,從根節點開始依次劃分二維空間區域直到左右孩子均為空指標。
tnode* buildkdtree(std::vectorpointsdata, int size, tnode* t)
else
}
一棵樹便建立完畢。我們先依靠這棵樹進行最近鄰的查詢,最近鄰的方法和二叉樹的深度遍歷一樣,利用乙個棧,每當往下延伸一層,便將該節點放入棧中。而往回溯源時,便把節點退棧。
float distance(struct data a, struct data b)
首先第一步,直接查詢直到葉節點,這一步將查詢點從根節點放入,依次根據**維比較,直至查詢到葉節點,那麼我們得到乙個疑似的「最近點」。
void findnearest(std::vectorpointsdata, struct data query)
else if(1 == t->split)
t->visited = true;
searchpath.push(t);
} //將此時的葉節點設為最近點
nearest = t;
//當前節點的指標,以及當前節點的父節點指標
tnode* current, *current_parent;
//臨時指標
tnode* temp;
//與當前節點的距離,以及與其兄**空間超平面的距離
double dist, dist_bro;
//如果某節點的兄**空間已被判斷過就略去並繼續回溯
bool bro_visited = false;
//向上回溯尋找是否具備更好的點
while(!searchpath.empty())
if(!searchpath.empty())
else if(current = current_parent->right)
if(!bro_visited)
else if(1 == current_parent->split)
//如果以查詢點為圓心,與當前節點距離為半徑畫的圓侵犯了兄弟節點的子空間,那麼跳到隔壁子空間去查詢
if(dist > dist_bro)
else if(1 == temp->split)
temp->visited = true;
searchpath.push(temp);
}//既然已經侵犯了兄**空間,那判斷這次搜尋到的葉節點是否比原來的葉節點更優,若是則將現在搜尋到的葉節點設為最近點
if(dist > distance(temp->data, query))
nearest = temp;
}//如果並未侵犯兄弟的子空間,那麼比較父節點與當前節點誰更優
else
}else}}}
int main()
{ struct data data;
std::vectorpointsdata;
int i = 1;
double x, y;
cout<<"請輸入x,y座標"<>x>>y)
{ cout<<"請輸入x,y座標"《如果是k近鄰的話,目前比較好的方法是利用優先順序佇列來維護k個最近點,當查詢到比佇列中更好的點時則將末尾的節點拿出,這就是大頂堆的演算法。
先佔坑,明天再寫。
KNN的實現 KD樹
實現knn時,主要考慮的問題是如何對訓練資料進行快速近鄰搜尋.這點在特徵空間的維數大及訓練資料容量大時尤其必要.knn最簡單的實現方法是線性掃瞄 linear scan 這時要計算輸入例項與每乙個訓練例項的距離.當訓練集很大時,計算非常耗時,這種方法是不可行的.為了提高knn搜尋的效率,可以考慮使用...
KNN演算法和KD樹
knn k nearestneighbor 鄰近演算法,或者說k最近鄰分類演算法 是資料探勘分類技術中最簡單的方法之一。所謂k最近鄰,就是k個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。knn演算法的核心思想是如果乙個樣本在特徵空間中的k個最相鄰的樣本中的大多數屬於某乙個類別,...
KNN原理及python實現 kd樹
覺得自己完全看懂和做出來是兩回事,希望自己可以堅持將機器學習演算法基本都復現出來,並有時間進行時間空間複雜度的優化,用matlab梳理完思路後有時間再用python寫一遍,畢竟我是乙個厲害的小女子哈哈哈。如果你閱讀我的文章有什麼疑問,或是任何學術討論,歡迎和我交流 ianqi1994 163.com...