最近研究KNN,找到了一些优秀的源码,贴出来,做个笔记吧。

  

 #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

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

  1. KNN算法的R语言实现

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

  2. kd树和knn算法的c语言实现

    基于kd树的knn的实现原理可以参考文末的链接,都是一些好文章. 这里参考了别人的代码.用c语言写的包括kd树的构建与查找k近邻的程序. code: #include<stdio.h> # ...

  3. 数据分析与挖掘 - R语言:KNN算法

    一个简单的例子!环境:CentOS6.5Hadoop集群.Hive.R.RHive,具体安装及调试方法见博客内文档. KNN算法步骤:需对所有样本点(已知分类+未知分类)进行归一化处理.然后,对未知分 ...

  4. MLlearning(1)——kNN算法

    这篇文章讲kNN(k近邻,k-Nearest Neighbour).这是一种lazy-learning,实现方便,很常用的分类方法.约定n为样本集中的样本数,m为样本的维度,则这个算法的训练复杂度为0 ...

  5. KNN算法 - 数据挖掘算法(3)

    (2017-04-10 银河统计) KNN算法即K Nearest Neighbor算法.这个算法是机器学习里面一个比较经典的.相对比较容易理解的算法.其中的K表示最接近自己的K个数据样本.KNN算法 ...

  6. 【机器学习】机器学习入门01 - kNN算法

    0. 写在前面 近日加入了一个机器学习的学习小组,每周按照学习计划学习一个机器学习的小专题.笔者恰好近来计划深入学习Python,刚刚熟悉了其基本的语法知识(主要是与C系语言的差别),决定以此作为对P ...

  7. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  8. KNN算法

    1.算法讲解 KNN算法是一个最基本.最简单的有监督算法,基本思路就是给定一个样本,先通过距离计算,得到这个样本最近的topK个样本,然后根据这topK个样本的标签,投票决定给定样本的标签: 训练过程 ...

  9. kNN算法python实现和简单数字识别

    kNN算法 算法优缺点: 优点:精度高.对异常值不敏感.无输入数据假定 缺点:时间复杂度和空间复杂度都很高 适用数据范围:数值型和标称型 算法的思路: KNN算法(全称K最近邻算法),算法的思想很简单 ...

随机推荐

  1. ASP.NET Core 项目简单实现身份验证及鉴权

    ASP.NET Core 身份验证及鉴权 目录 项目准备 身份验证 定义基本类型和接口 编写验证处理器 实现用户身份验证 权限鉴定 思路 编写过滤器类及相关接口 实现属性注入 实现用户权限鉴定 测试 ...

  2. 4-3 重构发送post请求

    当创建好一个post请求后 怎么测试呢?

  3. 【Python】 Python3 环境搭建

    Python是一种计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的.大型项目的开发. Windo ...

  4. Redis讲解以及测试要点

    一.redis 简介 redis适合放一些频繁使用,比较热的数据,因为是放在内存中,读写速度都非常快,一般会应用在下面一些场景,排行榜.计数器.消息队列推送.好友关注.粉丝. 首先要知道mysql存储 ...

  5. JavaScript中的Undefined / Null 类型相关说明

    1,综述: ※Undefined 和 Null是JavaScript中的两种数据类型(其他的类型还有:Boolean, String, Number, Object). ※Undefined类型只有一 ...

  6. JAVA 8 主要新特性 ----------------(五)Lambda方法引用与构造器引用

    一.Lambda方法引用 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!) 方法引用: 使用操作符 “::” 将 ...

  7. Django之路

    备注:本套笔记内容来源于互联网,只做学习使用,如有侵权请联系本笔记作者. 资料内容 Django之路(一)——什么是Web开发 Django之路(二)——Django初识 Django之路(三)——U ...

  8. ajax动态刷新的元素,导致绑定事件失效

    jquery事件绑定有2种方式: 1,普通事件绑定: $('元素').click(function(){}); 2, 事件代理或者叫事件委托 $('#chatPanelList').on('click ...

  9. JavaScript基础视频教程总结(091-100章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. 转发对python装饰器的理解

    [Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考   原文  http://blog.csdn.net/sxw3718401/article/details/3951958 ...