1. 程式人生 > >kd樹和knn演算法的c語言實現

kd樹和knn演算法的c語言實現

本文轉載自http://www.cnblogs.com/LCcnblogs/p/6169136.html

樓主正在學習機器學習演算法,歡迎學習交流。

#include<stdio.h>

#include<stdlib.h>
#include<math.h>
#include<time.h>


typedef struct{//資料維度
    double x;
    double y;
}data_struct;


typedef struct kd_node{
    data_struct split_data;//資料結點
    int split;//分裂維
    struct kd_node *left;//由位於該結點分割超面左子空間內所有資料點構成的kd-tree
    struct kd_node *right;//由位於該結點分割超面右子空間內所有資料點構成的kd-tree
}kd_struct;


//用於排序
int cmp1( const void *a , const void *b )
{
    return (*(data_struct *)a).x > (*(data_struct *)b).x ? 1:-1;
}
//用於排序
int cmp2( const void *a , const void *b )
{
    return (*(data_struct *)a).y > (*(data_struct *)b).y ? 1:-1;
}
//計算分裂維和分裂結點
void choose_split(data_struct data_set[],int size,int dimension,int *split,data_struct *split_data)
{
    int i;
    data_struct *data_temp;
    data_temp=(data_struct *)malloc(size*sizeof(data_struct));
    for(i=0;i<size;i++)   //data_temp臨時儲存資料集
        data_temp[i]=data_set[i];
    static int count=0;//設為靜態
    *split=(count++)%dimension;//分裂維,在第split維上進行劃分
    if((*split)==0) qsort(data_temp,size,sizeof(data_temp[0]),cmp1);  //qsort為內建快速排序(待排陣列,待排陣列長度,陣列元素大小,比較大小的函式的指標)
    else qsort(data_temp,size,sizeof(data_temp[0]),cmp2);  //split=0代表1維,=1代表2維
    *split_data=data_temp[(size-1)/2];//分裂結點排在中位
}
//判斷兩個資料點是否相等
int equal(data_struct a,data_struct b){
    if(a.x==b.x && a.y==b.y)    return 1;
    else    return 0;
}
//建立KD樹
kd_struct *build_kdtree(data_struct data_set[],int size,int dimension,kd_struct *T)
{
    if(size==0) return NULL;//遞迴出口
    else{
        int sizeleft=0,sizeright=0;
        int i,split;
        data_struct split_data;
        choose_split(data_set,size,dimension,&split,&split_data);
        data_struct data_right[size];
        data_struct data_left[size];


        if (split==0){//x維
            for(i=0;i<size;++i){
                if(!equal(data_set[i],split_data) && data_set[i].x <= split_data.x){//比分裂結點小
                    data_left[sizeleft].x=data_set[i].x;
                    data_left[sizeleft].y=data_set[i].y;
                    sizeleft++;//位於分裂結點的左子空間的結點數
                }
                else if(!equal(data_set[i],split_data) && data_set[i].x > split_data.x){//比分裂結點大
                    data_right[sizeright].x=data_set[i].x;
                    data_right[sizeright].y=data_set[i].y;
                    sizeright++;//位於分裂結點的右子空間的結點數
                }
            }
        }
        else{//y維
            for(i=0;i<size;++i){
                if(!equal(data_set[i],split_data) && data_set[i].y <= split_data.y){
                    data_left[sizeleft].x=data_set[i].x;
                    data_left[sizeleft].y=data_set[i].y;
                    sizeleft++;
                }
                else if (!equal(data_set[i],split_data) && data_set[i].y > split_data.y){
                    data_right[sizeright].x = data_set[i].x;
                    data_right[sizeright].y = data_set[i].y;
                    sizeright++;
                }
            }
        }
        T=(kd_struct *)malloc(sizeof(kd_struct));
        T->split_data.x=split_data.x;
        T->split_data.y=split_data.y;
        T->split=split;
        T->left=build_kdtree(data_left,sizeleft,dimension,T->left);//左子空間
        T->right=build_kdtree(data_right,sizeright,dimension,T->right);//右子空間
        return T;//返回指標
    }
}
//計算歐氏距離
double compute_distance(data_struct a,data_struct b){
    double tmp=pow(a.x-b.x,2.0)+pow(a.y-b.y,2.0);
    return sqrt(tmp);
}
//搜尋1近鄰
void search_nearest(kd_struct *T,int size,data_struct test,data_struct *nearest_point,double *distance)
{
    int path_size;//搜尋路徑內的指標數目
    kd_struct *search_path[size];//搜尋路徑儲存各結點的指標
    kd_struct* psearch=T;
    data_struct nearest;//最近鄰的結點
    double dist;//查詢結點與最近鄰結點的距離
    search_path[0]=psearch;//初始化搜尋路徑
    path_size=1;
    while(psearch->left!=NULL || psearch->right!=NULL){
        if (psearch->split==0){
            if(test.x <= psearch->split_data.x)//如果小於就進入左子樹
                psearch=psearch->left;
            else
                psearch=psearch->right;
        }
        else{
            if(test.y <= psearch->split_data.y)//如果小於就進入右子樹
                psearch=psearch->left;
            else
                psearch=psearch->right;
        }
        search_path[path_size++]=psearch;//將經過的分裂結點儲存在搜尋路徑中
    }
    //取出search_path最後一個元素,即葉子結點賦給nearest
    nearest.x=search_path[path_size-1]->split_data.x;
    nearest.y=search_path[path_size-1]->split_data.y;
    path_size--;//search_path的指標數減一
    dist=compute_distance(nearest,test);//計算與該葉子結點的距離作為初始距離


    //回溯搜尋路徑
    kd_struct* pback;
    while(path_size!=0){
        pback=search_path[path_size-1];//取出search_path最後一個結點賦給pback
        path_size--;//search_path的指標數減一


        if(pback->left==NULL && pback->right==NULL){//如果pback為葉子結點
            if(dist>compute_distance(pback->split_data,test)){
                nearest=pback->split_data;
                dist=compute_distance(pback->split_data,test);
            }
        }
        else{//如果pback為分裂結點
            int s=pback->split;
            if(s==0){//x維
                if(fabs(pback->split_data.x-test.x)<dist){//若以查詢點為中心的圓(球或超球),半徑為dist的圓與分割超平面相交,那麼就要跳到另一邊的子空間去搜索
                    if(dist>compute_distance(pback->split_data,test)){
                        nearest=pback->split_data;
                        dist=compute_distance(pback->split_data, test);
                    }
                    if(test.x<=pback->split_data.x)//若查詢點位於pback的左子空間,那麼就要跳到右子空間去搜索
                        psearch=pback->right;
                    else
                        psearch=pback->left;//若以查詢點位於pback的右子空間,那麼就要跳到左子空間去搜索
                    if(psearch!=NULL)
                        search_path[path_size++]=psearch;//psearch加入到search_path中
                }
            }
            else {//y維
                if(fabs(pback->split_data.y-test.y)<dist){//若以查詢點為中心的圓(球或超球),半徑為dist的圓與分割超平面相交,那麼就要跳到另一邊的子空間去搜索
                    if(dist>compute_distance(pback->split_data,test)){
                        nearest=pback->split_data;
                        dist=compute_distance(pback->split_data,test);
                    }
                    if(test.y<=pback->split_data.y)//若查詢點位於pback的左子空間,那麼就要跳到右子空間去搜索
                        psearch=pback->right;
                    else
                        psearch=pback->left;//若查詢點位於pback的的右子空間,那麼就要跳到左子空間去搜索
                    if(psearch!=NULL)
                        search_path[path_size++]=psearch;//psearch加入到search_path中
                }
            }
        }
    }


    (*nearest_point).x=nearest.x;//最近鄰
    (*nearest_point).y=nearest.y;
    *distance=dist;//距離
}


int main()
{
    int n=6;//資料個數
    data_struct nearest_point;
    double distance;
    kd_struct *root=NULL;
    data_struct data_set[6]={{2,3},{5,4},{9,6},{4,7},{8,1},{7,2}};//資料集
    data_struct test={7.1,2.1};//查詢點
    root=build_kdtree(data_set,n,2,root);


    search_nearest(root,n,test,&nearest_point,&distance);
    printf("nearest neighbor:(%.2f,%.2f)\ndistance:%.2f \n",nearest_point.x,nearest_point.y,distance);
    return 0;
}
/*                    x          5,4
                                /    \
                      y       2,3    7.2
                                \    /  \
                      x        4,7  8.1 9.6
*/

相關推薦

kdknn演算法c語言實現

本文轉載自http://www.cnblogs.com/LCcnblogs/p/6169136.html 樓主正在學習機器學習演算法,歡迎學習交流。 #include<stdio.h> #include<stdlib.h> #include<

基於kdKNN演算法實現

記得大三初期,剛從大連理工大學回來,眼巴巴的望著同學各自都有著落了,就我一副“初出茅廬,不諳世事”的樣子,於是不得不覥著臉厚著皮去找老師,懇求他讓我去海洋所實習。他給我的第一份差事便是將幾個G的圖片裡的數字輸入到excel,我整整輸了一個國慶節假日。當時就在到處

KD+BBF+KNN使用C#實現(1)

       最近研究了一下KD樹,以及在此基礎之上進行的改進BBF方法,以及如何利用BBF進行KNN。當然我還是主要參照很厲害的人物文章,程式碼利用C#實現了而已。        在這裡對我幫助最大的網址如下:      這篇文章主要講的就是K近鄰,距離度量,KD樹,以及

先來先服務高響應比優先排程演算法C語言實現

#include <stdio.h> #include <stdlib.h> #include <string.h> #define WAIT "Wait"//就緒狀態 #define RUN "Run"//執行狀態 #define FINISH "Finish"//完

連結串列中的頭尾節點/指標的常規用法(來自:演算法:C語言實現)

下面是基本連結串列處理操作的5種常規用法的實現.這類程式碼用於內嵌連結串列處理程式碼的簡單應用中 迴圈,永遠非空 頭插入 head->next = head; 在x節點後插入t節點 t->next = x->next, x->next = t; 刪

數據結構11: 棧(Stack)的概念應用及C語言實現

next ret 額外 轉換 lib 順序存儲 順序棧 就是 函數 棧,線性表的一種特殊的存儲結構。與學習過的線性表的不同之處在於棧只能從表的固定一端對數據進行插入和刪除操作,另一端是封死的。 圖1 棧結構示意圖 由於棧只有一邊開口存取數據,稱開口的那一端

SHA-1演算法C語言實現

> 程式碼轉載自:https://blog.csdn.net/testcs_dn/article/details/25771377?locationNum=13&fps=1 > 感謝博主分享 #include<stdio.h> void creat_w(uns

頁面置換演算法——最近最久未使用演算法(c語言實現)

作業系統實驗:用C語言程式設計實現最近最久未使用置換演算法(LRU) 最近最久未使用置換演算法(LRU),全稱Least Recently Used,是一種頁面置換演算法。 對於在記憶體中但又不用的資料塊(記憶體塊)叫做LRU,作業系統會根據哪些資料屬於LRU而將其移出記憶體而騰出空間來載入另外

建立雙向連結串列的演算法——C語言實現

建立雙向連結串列的演算法——C語言實現 雙向連結串列也叫雙鏈表,是連結串列的一種,它的每個節點包含兩個指標,分別指向直接後繼和直接前驅(頭節點的前驅指空,尾節點的後繼指空)。所以,從雙向連結串列中的任意一個非前驅非後繼節點開始,都能很方便地訪問它的前驅和後繼節點。 實際上如果熟練掌握了單向連

差分進化演算法 C語言實現

之前的一篇中貼出了自己研究生期間C實現的基本粒子群演算法,執行速度顯然要比其他的高階語言快,這也是各個程式語言之間的差別,現在對於曾經輝煌過的差分進化演算法進行C語言實現。變異策略採用DE/rand/1,這個是最常見的。有錯誤之處請之處。 /***************D

氣泡排序演算法C語言實現

第一部分   排序方法介紹 常用的排序方法:氣泡排序,選擇排序,插入排序及希爾排序等。        氣泡排序是常用的一種排序方法,其基本方法就是逐次比較。即一次比較兩個數,若它們的順序錯誤,則交換;重複進行,知道沒有需要交換為止。 以升序排序為例:        1.

MD5加密演算法C語言實現

md5.h #ifndef MD5_H #define MD5_H typedef struct { unsigned int count[2]; unsigned int state[4]; unsigned char buffe

磁碟排程演算法C語言實現

最短尋道時間優先(SSTF)演算法。要求訪問的磁軌,與當前磁頭所在的磁軌距離最近,以使每次的尋道時間最短。掃描排程(SCAN)演算法。該演算法不僅考慮到欲訪問的磁軌與當前磁軌間的距離,更優先考慮的是磁頭當前的移動方向。例如,當磁頭正在自裡向外移動時,SCAN演算法所考慮的下一

非常值得一看—九種濾波演算法C語言實現

關注“嵌入式軟體開發學習圈”免費獲取更多學習教程 今天帶著大家學習濾波演算法c語言(九種濾波演算法)實現,以及程式碼,大家可以學習瞭解下。。。。 1.限幅濾波演算法(程式判斷濾波演算法) 方法解析: 根據經驗判斷,確定兩次取樣允許的最

作業排程之先來先服務演算法C語言實現

程式碼如下 /*    @author WellsLiu    @url liuyanzhao.com*/#include"stdio.h"#include"stdlib.h"typedef st

處理機排程演算法C語言實現(註釋得當!!)

/* created by herbert on 10 Nov */ #include <iostream> #include <queue> #include <algorithm> #include <c

最短路徑之Dijkstra演算法 C語言實現

Dijkstra演算法(單源點路徑演算法,要求:圖中不存在負權值邊): 步驟: a.  初始時,S只包含源點,即S={v},v的距離為0。U包含除v外的其他頂點,即: U={其餘頂點},若v與U中頂點u有邊,則u的距離設定為相應的權值,若u v之間不存在邊,則    

SHA-256演算法 C語言實現

#include <stdio.h> #include <stdlib.h> #define SHA256_ROTL(a,b) (((a>>(32-b))&(0x7fffffff>>(31-b)))|(a<<

哈夫曼壓縮演算法C語言實現——步驟,詳細註釋原始碼

哈夫曼壓縮演算法的詳細實現步驟: 1、定義哈夫曼樹節點,用結構體。 2、利用C語言檔案讀寫,統計字元個數。 3、根據字元個數建立哈夫曼樹(不懂haffman資料結構的自己查下資料,我這裡就不再重複了) 4、根據哈夫曼樹為每個出現的字元編碼 5、壓縮:這裡涉及到位操作,用ch