kd树 C++实现
参考:百科kd-tree
/*
* kdtree.h
*
* Created on: Mar 3, 2017
* Author: wxquare
*/ #ifndef KDTREE_H_
#define KDTREE_H_ #include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <stack> template<typename T>
class KdTree {
struct kdNode {
std::vector<T> vec; //data
//split attribute,-1 means leftNode,no split attribute
int splitAttribute;
kdNode* lChild;
kdNode* rChild;
kdNode* parent; kdNode(std::vector<T> v = { }, int split = , kdNode* lch = nullptr,
kdNode* rch = nullptr, kdNode* par = nullptr) :
vec(v), splitAttribute(split), lChild(lch), rChild(rch), parent(par) {}
}; private:
kdNode *root; public:
KdTree() {
root = nullptr;
} KdTree(std::vector<std::vector<T>>& data) {
root = createKdTree(data);
} //matrix transpose
std::vector<std::vector<T>> transpose(std::vector<std::vector<T>>& data) {
int m = data.size();
int n = data[].size();
std::vector<std::vector<T>> trans(n, std::vector<T>(m, ));
for (int i = ; i < n; i++) {
for (int j = ; j < m; j++) {
trans[i][j] = data[j][i];
}
}
return trans;
} //get variance of a vector
double getVariance(std::vector<T>& vec) {
int n = vec.size();
double sum = ;
for (int i = ; i < n; i++) {
sum = sum + vec[i];
}
double avg = sum / n;
sum = ; //sum of squaNN
for (int i = ; i < n; i++) {
sum += pow(vec[i] - avg, ); //#include<cmath>
}
return sum / n;
} //According to maximum variance get split attribute.
int getSplitAttribute(const std::vector<std::vector<T>>& data) {
int k = data.size();
int splitAttribute = ;
double maxVar = getVariance(data[]);
for (int i = ; i < k; i++) {
double temp = getVariance(data[i]);
if (temp > maxVar) {
splitAttribute = i;
maxVar = temp;
}
}
return splitAttribute;
} //find middle value
T getSplitValue(std::vector<T>& vec) {
std::sort(vec.begin(), vec.end());
return vec[vec.size() / ];
} //compute distance of two vector
static double getDistance(std::vector<T>& v1, std::vector<T>& v2) {
double sum = ;
for (size_t i = ; i < v1.size(); i++) {
sum += pow(v1[i] - v2[i], );
}
return sqrt(sum) / v1.size();
} kdNode* createKdTree(std::vector<std::vector<T>>& data) {
//the number of samples(data)
if (data.empty()) return nullptr;
int n = data.size();
if (n == ) {
return new kdNode(data[], -); //叶子节点
} //get split attribute and value
std::vector<std::vector<T>> data_T = transpose(data);
int splitAttribute = getSplitAttribute(data_T);
int splitValue = getSplitValue(data_T[splitAttribute]); //split data according splitAttribute and splitValue
std::vector<std::vector<T>> left;
std::vector<std::vector<T>> right; int flag = ; //the first sample's splitValue become splitnode
kdNode *splitNode;
for (int i = ; i < n; i++) {
if (flag == && data[i][splitAttribute] == splitValue) {
splitNode = new kdNode(data[i]);
splitNode->splitAttribute = splitAttribute;
flag = ;
continue;
}
if (data[i][splitAttribute] <= splitValue) {
left.push_back(data[i]);
} else {
right.push_back(data[i]);
}
} splitNode->lChild = createKdTree(left);
splitNode->rChild = createKdTree(right);
return splitNode;
} //search nearest neighbor
/* 参考百度百科
* 从root节点开始,DFS搜索直到叶子节点,同时在stack中顺序存储已经访问的节点。
如果搜索到叶子节点,当前的叶子节点被设为最近邻节点。
然后通过stack回溯:
如果当前点的距离比最近邻点距离近,更新最近邻节点.
然后检查以最近距离为半径的圆是否和父节点的超平面相交.
如果相交,则必须到父节点的另外一侧,用同样的DFS搜索法,开始检查最近邻节点。
如果不相交,则继续往上回溯,而父节点的另一侧子节点都被淘汰,不再考虑的范围中.
当搜索回到root节点时,搜索完成,得到最近邻节点。
*/
std::vector<T> searchNearestNeighbor(std::vector<T>& target,kdNode* start) {
std::vector<T> NN;
std::stack<kdNode*> searchPath;
kdNode* p = start;
while (p->splitAttribute != -) {
searchPath.push(p);
int splitAttribute = p->splitAttribute;
if (target[splitAttribute] <= p->vec[splitAttribute]) {
p = p->lChild;
} else {
p = p->rChild;
}
}
NN = p->vec;
double mindis = KdTree::getDistance(target, NN); kdNode* cur;
double dis;
while (!searchPath.empty()) {
cur = searchPath.top();
searchPath.pop();
dis = KdTree::getDistance(target, cur->vec);
if (dis < mindis) {
mindis = dis;
NN = cur->vec;
//判断以target为中心,以dis为半径的球是否和节点的超平面相交
if (cur->vec[cur->splitAttribute]
>= target[cur->splitAttribute] - dis
&& cur->vec[cur->splitAttribute]
<= target[cur->splitAttribute] + dis) {
std::vector<T> nn = searchNearestNeighbor(target,
cur->lChild);
if (KdTree::getDistance(target, nn)
< KdTree::getDistance(target, NN)) {
NN = nn;
}
}
}
}
return NN;
} std::vector<T> searchNearestNeighbor(std::vector<T>& target) {
std::vector<T> NN;
NN = searchNearestNeighbor(target, root);
return NN;
} void print(kdNode* root) {
std::cout << "[";
if (root->lChild) {
std::cout << "left:";
print(root->lChild);
} if (root) {
std::cout << "(";
for (size_t i = ; i < root->vec.size(); i++) {
std::cout << root->vec[i];
if (i != (root->vec.size() - ))
std::cout << ",";
}
std::cout << ")";
} if (root->rChild) {
std::cout << "right:";
print(root->rChild);
}
std::cout << "]";
} }; #endif /* KDTREE_H_ */
kd树 C++实现的更多相关文章
- 利用KD树进行异常检测
软件安全课程的一次实验,整理之后发出来共享. 什么是KD树 要说KD树,我们得先说一下什么是KNN算法. KNN是k-NearestNeighbor的简称,原理很简单:当你有一堆已经标注好的数据时,你 ...
- 2016 ICPC青岛站---k题 Finding Hotels(K-D树)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5992 Problem Description There are N hotels all over ...
- kd树和knn算法的c语言实现
基于kd树的knn的实现原理可以参考文末的链接,都是一些好文章. 这里参考了别人的代码.用c语言写的包括kd树的构建与查找k近邻的程序. code: #include<stdio.h> # ...
- PCL点云库:Kd树
Kd树按空间划分生成叶子节点,各个叶子节点里存放点数据,其可以按半径搜索或邻区搜索.PCL中的Kd tree的基础数据结构使用了FLANN以便可以快速的进行邻区搜索.FLANN is a librar ...
- KNN算法与Kd树
最近邻法和k-近邻法 下面图片中只有三种豆,有三个豆是未知的种类,如何判定他们的种类? 提供一种思路,即:未知的豆离哪种豆最近就认为未知豆和该豆是同一种类.由此,我们引出最近邻算法的定义:为了判定未知 ...
- k临近法的实现:kd树
# coding:utf-8 import numpy as np import matplotlib.pyplot as plt T = [[2, 3], [5, 4], [9, 6], [4, 7 ...
- 从K近邻算法谈到KD树、SIFT+BBF算法
转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...
- bzoj 3489: A simple rmq problem k-d树思想大暴力
3489: A simple rmq problem Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 551 Solved: 170[Submit][ ...
- k近邻法的C++实现:kd树
1.k近邻算法的思想 给定一个训练集,对于新的输入实例,在训练集中找到与该实例最近的k个实例,这k个实例中的多数属于某个类,就把该输入实例分为这个类. 因为要找到最近的k个实例,所以计算输入实例与训练 ...
- bzoj 3053 HDU 4347 : The Closest M Points kd树
bzoj 3053 HDU 4347 : The Closest M Points kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...
随机推荐
- 博客和Github简单练习
我的第一篇博客 1.首先是自我介绍 姓名:孙弘毅 班级:网工142 学号:1413042050 兴趣:游戏,看书 至于我写了多少代码我也不清楚,反正不多 2.Github 注册流程 (1)百度Git ...
- 前端与HTTP
本文整理在,我的github 上.欢迎Star. 各版本的http 发展 在HTTP建立之初,主要是为了传输超文本标记语言(HTML)文档.随着时代的发展,也进行了若干次演进.下图是各个版本发布的时间 ...
- merge sort 的javascript实现
递归 上一篇blog里,用js实现了quicksort算法,quicksort算法是一个递归调用过程. 递归是一种非常强大的编程思想,它广泛的的存在于各种语言当中,尤其lisp的各种方言中,大量的使用 ...
- virtualbox上硬盘安装coreos
网址: http://www.serfdom.cn/index.php/archives/4/ http://www.360doc.com/content/14/1118/10/15077656_42 ...
- 1、ASP.NET Core2.0之Model、View、Controller
一.新建空项目 打开VS2017,新建→项目,选择如下: 点击,确定,弹出的界面选择如下: 选择空项目,因为选择其他的话会自动生成很多用不到的类,显得项目不够“清爽”,ASP.NET Core选择2. ...
- iOS 添加 Watch OS 1 应用后无法运行 An error was encountered while running (Domain = LaunchServicesError, Code = 0)
在 iOS 应用基础上我添加了一个 Watch OS 2 应用,运行良好.又加了一个 Watch OS 1 应用,然后就所有 Target 都不能运行了. 运行时说 An error was enco ...
- Hibernate 框架学习
什么是hibernate框架? 1.它是应用在javaee 三层架构中的dao层 它的底层就是JDBC 它对JDBC进行了封装,好处就是不用写jdbc的代码,和sql语句,它是一个开源的轻量级框架,现 ...
- JAVA中Date类的使用
一. Date类 Date类对象的创建: 1.创建一个当前时间的Date对象 //创建一个代表系统当前日期的Date对象 Date d = new Date(); 2.创建一个我们指定的时间的Date ...
- spring-boot打包,引入外部jar包问题
这是我引入的外部jar包,打包的时候找不到外部jar包路径 弄了好久 在lib下引入外部jar包,运行没问题,但是打包是出现问题了,具体解决办法 再pom中加入如下配置,告诉maven导入本地jar ...
- Java初学者的学习路线建议
java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈 ...