参考:百科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++实现的更多相关文章

  1. 利用KD树进行异常检测

    软件安全课程的一次实验,整理之后发出来共享. 什么是KD树 要说KD树,我们得先说一下什么是KNN算法. KNN是k-NearestNeighbor的简称,原理很简单:当你有一堆已经标注好的数据时,你 ...

  2. 2016 ICPC青岛站---k题 Finding Hotels(K-D树)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5992 Problem Description There are N hotels all over ...

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

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

  4. PCL点云库:Kd树

    Kd树按空间划分生成叶子节点,各个叶子节点里存放点数据,其可以按半径搜索或邻区搜索.PCL中的Kd tree的基础数据结构使用了FLANN以便可以快速的进行邻区搜索.FLANN is a librar ...

  5. KNN算法与Kd树

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

  6. k临近法的实现:kd树

    # coding:utf-8 import numpy as np import matplotlib.pyplot as plt T = [[2, 3], [5, 4], [9, 6], [4, 7 ...

  7. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  8. 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][ ...

  9. k近邻法的C++实现:kd树

    1.k近邻算法的思想 给定一个训练集,对于新的输入实例,在训练集中找到与该实例最近的k个实例,这k个实例中的多数属于某个类,就把该输入实例分为这个类. 因为要找到最近的k个实例,所以计算输入实例与训练 ...

  10. bzoj 3053 HDU 4347 : The Closest M Points kd树

    bzoj 3053 HDU 4347 : The Closest M Points  kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...

随机推荐

  1. Java Web系列:JAAS认证和授权基础

    1.认证和授权概述 (1)认证:对用户的身份进行验证. .NET基于的RBS(参考1)的认证和授权相关的核心是2个接口System.Security.Principal.IPrincipal和Syst ...

  2. Gluster 常用命令

    Gluster 常用命令1 服务器节点# gluster peer status //查看所有节点信息,显示时不包括本节点 # gluster peer probe NODE-NAME //添加节点 ...

  3. C#发送邮件及注意事项

    //参数配置 static readonly string smtpServer = System.Configuration.ConfigurationManager.AppSettings[&qu ...

  4. C#冒泡排序(完整代码)

    百度百科 冒泡排序是笔试面试经常考的内容,虽然它是这些算法里排序速度最慢的 原理:从头开始,每一个元素和它的下一个元素比较,如果它大,就将它与比较的元素交换,否则不动. 这意味着,大的元素总是在向后慢 ...

  5. WPF透明窗体不支持缩放解决方案

    方案一 WPF中的无边框透明窗体,由于没有边并且透明,窗体无法进行缩放操作,今天来讲解如何解决这个问题. 先说一下思路,我们先手为该窗体添加4个边,4个角用于缩放操作,然后再为他们写事件,完成拖放操作 ...

  6. 修改 nginx 默认端口

     修改 nginx 默认端口 nginx 解压目录下的  conf 目录下的 nginx.conf 修改对应端口

  7. junit所需要的jar包

    hamcrest-core-1.1.jar junit-4.12.jar http://central.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/ ...

  8. vue 路由传参

      mode:路由的形式 用的哪种路由 1.hash 路由 会带#号的哈希值 默认是hash路由   2.history路由 不会带#的     单页面开发首屏加载慢怎么解决?单页面开发首屏加载白屏怎 ...

  9. django 模型中 class Meta 内 各种属性的用法

    Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.下面对此作一总结: abstract 这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会相应数据库表的 ...

  10. 50余本中外Python电子教程及源码下载地址

    链接:http://pan.baidu.com/s/1c0VTwsC 密码:hapu