基于kd树的knn的实现原理可以参考文末的链接,都是一些好文章。

  这里参考了别人的代码。用c语言写的包括kd树的构建与查找k近邻的程序。

  code:

 #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 ? :-;
}
//用于排序
int cmp2( const void *a , const void *b )
{
return (*(data_struct *)a).y > (*(data_struct *)b).y ? :-;
}
//计算分裂维和分裂结点
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=;i<size;i++)
data_temp[i]=data_set[i];
static int count=;//设为静态
*split=(count++)%dimension;//分裂维
if((*split)==) qsort(data_temp,size,sizeof(data_temp[]),cmp1);
else qsort(data_temp,size,sizeof(data_temp[]),cmp2);
*split_data=data_temp[(size-)/];//分裂结点排在中位
}
//判断两个数据点是否相等
int equal(data_struct a,data_struct b){
if(a.x==b.x && a.y==b.y) return ;
else return ;
}
//建立KD树
kd_struct *build_kdtree(data_struct data_set[],int size,int dimension,kd_struct *T)
{
if(size==) return NULL;//递归出口
else{
int sizeleft=,sizeright=;
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==){//x维
for(i=;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=;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[]=psearch;//初始化搜索路径
path_size=;
while(psearch->left!=NULL || psearch->right!=NULL){
if (psearch->split==){
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-]->split_data.x;
nearest.y=search_path[path_size-]->split_data.y;
path_size--;//search_path的指针数减一
dist=compute_distance(nearest,test);//计算与该叶子结点的距离作为初始距离 //回溯搜索路径
kd_struct* pback;
while(path_size!=){
pback=search_path[path_size-];//取出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==){//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=;//数据个数
data_struct nearest_point;
double distance;
kd_struct *root=NULL;
data_struct data_set[]={{,},{,},{,},{,},{,},{,}};//数据集
data_struct test={7.1,2.1};//查询点
root=build_kdtree(data_set,n,,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 ;
}
/* x 5,4
/ \
y 2,3 7.2
\ / \
x 4,7 8.1 9.6
*/

参考:

  https://www.joinquant.com/post/2627?f=study&m=math

  https://www.joinquant.com/post/2843?f=study&m=math

  http://blog.csdn.net/zhl30041839/article/details/9277807

kd树和knn算法的c语言实现的更多相关文章

  1. knn算法的c语言实现

    最近研究KNN,找到了一些优秀的源码,贴出来,做个笔记吧. #include<stdio.h> #include<stdlib.h> #include<math.h> ...

  2. KNN算法的R语言实现

    近邻分类 简言之,就是将未标记的案例归类为与它们最近相似的.带有标记的案例所在的类. 应用领域: 1.计算机视觉:包含字符和面部识别等 2.推荐系统:推荐受众喜欢电影.美食和娱乐等 3.基因工程:识别 ...

  3. 深入浅出KNN算法(二) sklearn KNN实践

    姊妹篇: 深入浅出KNN算法(一) 原理介绍 上次介绍了KNN的基本原理,以及KNN的几个窍门,这次就来用sklearn实践一下KNN算法. 一.Skelarn KNN参数概述 要使用sklearnK ...

  4. 机器学习 KNN算法原理

    K近邻(K-nearst neighbors,KNN)是一种基本的机器学习算法,所谓k近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表.比如:判断一个人的人品,只需要观察 ...

  5. kd树的构建以及搜索

    构建算法 k-d树是一个二叉树,每个节点表示一个空间范围.表1给出的是k-d树每个节点中主要包含的数据结构. 表1 k-d树中每个节点的数据类型 域名 数据类型 描述 Node-data 数据矢量 数 ...

  6. KD树

    k-d树 在计算机科学里,k-d树( k-维树的缩写)是在k维欧几里德空间组织点的数据结构.k-d树可以使用在多种应用场合,如多维键值搜索(例:范围搜寻及最邻近搜索).k-d树是空间二分树(Binar ...

  7. 02-17 kd树

    目录 kd树 一.kd树学习目标 二.kd树引入 三.kd树详解 3.1 构造kd树 3.1.1 示例 3.2 kd树搜索 3.2.1 示例 四.kd树流程 4.1 输入 4.2 输出 4.3 流程 ...

  8. KNN算法与Kd树

    最近邻法和k-近邻法 下面图片中只有三种豆,有三个豆是未知的种类,如何判定他们的种类? 提供一种思路,即:未知的豆离哪种豆最近就认为未知豆和该豆是同一种类.由此,我们引出最近邻算法的定义:为了判定未知 ...

  9. 一看就懂的K近邻算法(KNN),K-D树,并实现手写数字识别!

    1. 什么是KNN 1.1 KNN的通俗解释 何谓K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1 ...

随机推荐

  1. AngularJs之六(服务)

    服务:AngularJS 中,服务是一个函数或对象,可在你的 AngularJS 应用中使用.AngularJS 内建了30 多个服务. 最常用的服务:$location  服务,  $http 服务 ...

  2. iOS--碎片知识锦集

    知识锦集day01 1.UIView的两个方法: sizeThatFits和 sizeToFit 官方文档上说: - (CGSize)sizeThatFits:(CGSize)size;     // ...

  3. javascript继承的三种模式

    javascript继承一般有三种模式:组合继承,原型式继承和寄生式继承: 1组合继承:javascript最为广泛的继承方式通过原型链实现对原型属性和方法的继承,通过构造函数实现对实例属性的继承,同 ...

  4. ASP.NET Core管道深度剖析[共4篇]

    之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET Core应用的很多特性,比 ...

  5. 创建 Pool & VIP - 每天5分钟玩转 OpenStack(122)

    上节完成了 LBaaS 配置,今天我们开始实现如下 LBaaS 环境. 环境描述如下: 1. 创建一个 Pool “web servers”. 2. 两个 pool member “WEB1” 和 “ ...

  6. 如何修改MySQL字符集

    首先,MySQL的字符集问题主要是两个概念,一个是Character Sets,一个是Collations,前者是字符内容及编码,后者是对前者进行比较操作的一些规则.这两个参数集可以在数据库实例.单个 ...

  7. eclipse打开文件所在目录

    设置 添加扩展工具,添加步骤如下: Run-->External Tools-->External Tools Configurations... new 一个 programlocati ...

  8. Apache Spark简单介绍、安装及使用

    Apache Spark简介 Apache Spark是一个高速的通用型计算引擎,用来实现分布式的大规模数据的处理任务. 分布式的处理方式可以使以前单台计算机面对大规模数据时处理不了的情况成为可能. ...

  9. WPF入门:XAML

    XAML是WPF技术中专门用于设计UI的语言 XAML优点最大的优点是将UI与逻辑代码剥离 创建第一个WPF应用程序 VS默认生成的WPF项目解决方案 Properties:里面主要包含了程序用到的一 ...

  10. Socket初识

    基础概念 Socket,套接字,本质是网络编程接口.提供网络通信的能力,实现不同虚拟机或不同计算机之间的通信.面向客户/服务(C/S)模型,socket是应用层和传输层之间的中间软件抽象层: 顶上三层 ...