KNN演算法的KD樹C 實現

2021-08-27 11:33:19 字數 2800 閱讀 2470

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...