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树的两种建树方式,即按照方差 ...
随机推荐
- [c# 20问] 1. 何时使用class与struct
POINTS struct为可以包含数据和函数的值类型 struct为值类型所以不需要堆(heap)而是在栈(stack)上分配空间 struct将数据直接存在struct中,而class只存引用类型 ...
- WPF显示Gif动画
WPF的Image控件不能很好的支持.gif文件.解决办法有如下2种. 1使用MediaElement <MediaElement Source="file://D:\anim.gif ...
- LightOJ 1138 Trailing Zeroes (III)(二分 + 思维)
http://lightoj.com/volume_showproblem.php?problem=1138 Trailing Zeroes (III) Time Limit:2000MS M ...
- EF6 使用SQLite Code First
SQLite是一款轻型关系型数据库,做一个小网站,用来替代sql server或者access数据库应该会是一个不错的选择. ASP.NET Entity Framework 6是微软平台的著名ORM ...
- how to remote debug in vs 2013
first download the debugger tools "rtools_setup_x64" start C:\Program Files\Microsoft Visu ...
- 比较有用的php代码片段
一 从网页中提取关键词 $meta = get_meta_tags('http://www.emoticode.net/'); $keywords = $meta['keywords']; // Sp ...
- 十一、linux文件系统权限详解
对于文件系统权限,我们前面已经讲解了一部分,这里就不在重复了. 1.修改文件权限有两种,一种是数字.一种是字母 (chmod 的修改只能是属主或者root) 数字: 修改目录权限和目录内所有文件的权限 ...
- [Swift实际操作]八、实用进阶-(2)Swift语言中的三种消息传递模式
本文将通过响应按钮的点击事件,来演示Target-Action消息传递机制,该机制主要用于响应用户的界面操作.打开创建的空白项目.然后在左侧的项目导航区,打开视图控制器的代码文件:ViewContro ...
- Markdown入门简介
参考 http://sspai.com/25137 作者: Te_Lee 文章来源: 少数派 Markdown入门简介(使用工具Haroopad) 一.使用的工具----haroopad(http:/ ...
- CentOS7基础建站指南(笔记)
由于前段时间腾讯云打折,所以买了一台小服务器,想着以后写几个小网站,博客什么的,但是一开始就遇到了难题,大概就是Linux服务器的配置问题,比如如何假设服务器,配置非root用户,配置服务器数据的非r ...