参考:百科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. 作业二:注册软件github

    注册Github

  2. solr特点五: MoreLikeThis(查找相似页面)

    在 Google 上尝试一个查询,您会注意到每一个结果都包含一个 “相似页面” 链接,单击该链接,就会发布另一个搜索请求,查找出与起初结果类似的文档.Solr 使用MoreLikeThisCompon ...

  3. 如何创建一个自己的.NET Core Global Tools

    索引 NET Core应用框架之BitAdminCore框架应用篇系列 框架演示:https://www.bitadmincore.com 框架源码:https://github.com/chenyi ...

  4. Winfrom PictureBox 设置图片自适应

    初始状态 Bitmap bm = new Bitmap(Image.FromStream(System.Net.WebRequest.Create(new Uri(result.Result)).Ge ...

  5. JPA之@GeneratedValue注解

    JPA的@GeneratedValue注解,在JPA中,@GeneratedValue注解存在的意义主要就是为一个实体生成一个唯一标识的主键(JPA要求每一个实体Entity,必须有且只有一个主键), ...

  6. Vulnhub Breach1.0

    1.靶机信息 下载链接 https://download.vulnhub.com/breach/Breach-1.0.zip 靶机说明 Breach1.0是一个难度为初级到中级的BooT2Root/C ...

  7. django入门-自定义管理界面-part7

    尊重作者的劳动,转载请注明作者及原文地址 http://www.cnblogs.com/txwsqk/p/6522854.html 完全翻译自官方文档 https://docs.djangoproje ...

  8. PHP 访问链接的3种方式

    对于php访问url的方法比价多,对于一些防护比较低的网站,可以轻易的实现刷网站浏览量的可能 1.fopen方式 function access_url($url) { if ($url=='') r ...

  9. SYN 洪泛攻击

    在 TCP 三次握手中,服务器为了响应一个收到的 SYN,分配并初始化连接变量和缓存.然后服务器发送一个 SYNACK 进行相应,并等待来自客户的 ACK 报文段. 如果某客户不发送 ACK 来完成三 ...

  10. 49.RocketMQ 双主搭建(本文非EamonSec原创)

    声明:本文非EamonSec原创,copy自网上下载的某个个文件 1.RocketMQ介绍 1.1. 简介 RocketMQ 是一款分布式.队列模型的消息中间件,具有以下特点: 能够保证严格的消息顺序 ...