参考:百科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. ASP.NET Core2使用Autofac实现IOC依赖注入竟然能如此的优雅简便

    初识ASP.NET Core的小伙伴一定会发现,其几乎所有的项目依赖都是通过依赖注入方式进行链式串通的.这是因为其使用了依赖注入 (DI) 的软件设计模式,代码的设计是遵循着“高内聚.低耦合”的原则, ...

  2. 不错的Django博客

    https://blog.csdn.net/chengqiuming/article/category/8453874 杜塞的个人网站 https://www.dusaiphoto.com/ 追梦人物 ...

  3. [javascript][翻译]使用javascript添加css rule

    来杭一周,收获很多,成长很多. 周六在搞一个插件的时候碰到需要动态添加伪元素的需求,搜了一下解决方案,有人用正则写出了读取伪元素的函数:我觉得倒是可以通过注入css rule的方式,来让预留有某些类的 ...

  4. CVE-2018-7600 Drupal核心远程代码执行漏洞分析

    0x01 漏洞介绍 Drupal是一个开源内容管理系统(CMS),全球超过100万个网站(包括政府,电子零售,企业组织,金融机构等)使用.两周前,Drupal安全团队披露了一个非常关键的漏洞,编号CV ...

  5. JS获取节点属性个数及值得方法

    var ex = node; ; for (var j in ex) { alert("" + myIndex + ".(<font color='blue'> ...

  6. [JXOI2017]颜色 线段树求点对贡献

    [JXOI2017]颜色 题目链接 https://www.luogu.org/problemnew/show/P4065 题目描述 可怜有一个长度为 n 的正整数序列 Ai,其中相同的正整数代表着相 ...

  7. GO学习笔记 - 变量在定义时没有明确的初始化时会赋值为“零值 ”。

    官方教程:https://tour.go-zh.org/basics/12 变量在定义时没有明确的初始化时会赋值为 零值 . 零值是: 数值类型为 0 , 布尔类型为 false , 字符串为 &qu ...

  8. C - Oil Deposits(dfs)

    点击打开链接 Oil Deposits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  9. CTF 介绍及杂项

    CTF(Capture The Flag)中文一般译作夺旗赛,在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式.CTF起源于1996年DEFCON全球黑客大会,以代替之前黑客们通过 ...

  10. [ActionScript 3.0] File下载工具

    更新数据原理,访问接口,将服务器数据抓取并下载到本地的临时文件夹,当所有下载完成,卸载客户端内容,出现升级界面,此时移动下载的内容到目标文件夹,移动完成再重新加载客户端,访问接口,下载文件,移动文件均 ...