C++ 清晰高效的三维范围树实现
我正在做这个项目,我必须在3d空间中搜索对象,效率是一个巨大的问题,我认为范围树非常适合我要做的事情,间隔树也可以,但我不会从树中删除任何内容,一旦我在3d空间中添加了所有对象,我将只使用该结构进行搜索 下面是我将如何使用该结构: 假设我有一个对象数组(我们称之为queryArr),每个对象有3个参数(x,y,z)。我有另一个非常大的对象数组(我们称之为totalArr),对象(>5000000个对象) 我在这里试图做的是给定queryArr的元素,找到最相似的元素(或者在totalArr中找到相同的元素)。在某些情况下,在totalArr中会有具有相同参数的对象,但在大多数情况下,不会有具有相同参数的对象 因此,我将搜索C++ 清晰高效的三维范围树实现,c++,algorithm,search,data-structures,range-tree,C++,Algorithm,Search,Data Structures,Range Tree,我正在做这个项目,我必须在3d空间中搜索对象,效率是一个巨大的问题,我认为范围树非常适合我要做的事情,间隔树也可以,但我不会从树中删除任何内容,一旦我在3d空间中添加了所有对象,我将只使用该结构进行搜索 下面是我将如何使用该结构: 假设我有一个对象数组(我们称之为queryArr),每个对象有3个参数(x,y,z)。我有另一个非常大的对象数组(我们称之为totalArr),对象(>5000000个对象) 我在这里试图做的是给定queryArr的元素,找到最相似的元素(或者在totalArr中找到
(x+10,y+10,z+10)
和(x-10,y-10,z-10)
之间的所有值。如果它没有产生任何结果,我将把x,y,z乘以2,然后再试一次,直到它产生一些结果
最简单的方法是一种简单的搜索方法,它的复杂度为O(N*M)(N=queryArr的大小,M=sie of totalArr)
,但这种方法速度非常慢,而且非常愚蠢
我认为距离树是一条路要走,但我自己从来没有实现过距离树,我不太明白距离树是如何在大于2的维度上工作的。那么,有谁知道射程树的一个很好的实现吗?我相信如果我有一个源代码,我就能理解它们是如何工作的
顺便说一句,如果你认为这个任务有一个比范围树更好的结构,请告诉我我愿意接受建议。(我已经考虑了kd树和区间树)
谢谢,我刚刚读了维基百科的文章。让我们看看我是否可以写一个n维范围树。因为任何值得在三维空间做的事情都值得在n空间做 所以n维范围树的基本部分是,它可以用低维范围树递归定义 一些属性类可以使用相对通用的值类型。专门化
element\u属性
以设置n维值的标量类型,并专门化get(T const&)
以获取n维值的i
th维
#include <memory>
#include <cstddef>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
void Assert(bool test) {
if (!test)
{
std::cout << "Assert failed" << std::endl;
exit(-1);
}
}
template<typename... Args>
struct Print {
static void Do(Args... args) {}
};
template<typename Arg, typename... Tail>
struct Print<Arg, Tail...> {
static void Do(Arg arg, Tail... args) {
std::cout << arg;
Print<Tail...>::Do(args...);
}
};
template<typename... Args>
void Debug(Args... args) {
std::cout << "DEBUG:[";
Print<Args...>::Do(args...);
std::cout << "]\n";
}
template<typename T>
struct element_properties {
typedef typename T::value_type value_type;
};
template<>
struct element_properties<int> {
typedef int value_type;
};
template<size_t d, typename T>
typename element_properties<T>::value_type get( T const & t );
template<size_t d>
typename element_properties<int>::value_type get( int i ) { return i; }
template<size_t d, typename U, typename A>
typename element_properties<std::vector<U,A>>::value_type get( std::vector<U,A> const& v) {
return v[d];
}
template<typename T, size_t dim, typename Order = std::less< typename element_properties<T>::value_type> >
struct range_tree {
typedef typename element_properties<T>::value_type value_type;
struct sorter {
bool operator()( T const& left, T const& right ) const {
return Order()( get<dim-1>(left), get<dim-1>(right) );
}
};
struct printer {
std::string operator()( T const& t ) const {
std::string retval = "[ ";
retval += print_elements( t );
retval += "]";
return retval;
}
std::string print_elements( T const& t ) const {
std::stringstream ss;
typedef typename range_tree<T, dim-1, Order>::printer next_printer;
ss << next_printer().print_elements(t);
ss << get<dim-1>(t) << " ";
return ss.str();
}
};
template<typename Iterator>
range_tree( Iterator begin, Iterator end ) {
std::sort( begin, end, sorter() );
root.reset( new tree_node( begin, end ) );
}
template<size_t n, typename Func>
void walk(Func f) const {
if (root) root->walk<n>(f);
}
template<size_t n, typename Func>
void walk(Func f) {
if (root) root->walk<n>(f);
}
struct tree_node {
std::unique_ptr< range_tree<T, dim-1, Order> > subtree;
T value;
template<size_t n, typename Func>
void walk(Func f) const {
if (n==dim && !left && !right)
f(value);
if (left)
left->walk<n>(f);
if (right)
right->walk<n>(f);
if (subtree)
subtree->walk<n>(f);
}
template<size_t n, typename Func>
void walk(Func f) {
if (n==dim && !left && !right)
f(value);
if (left)
left->walk<n>(f);
if (right)
right->walk<n>(f);
if (subtree)
subtree->walk<n>(f);
}
void find_path( T const& t, std::vector< tree_node const* >& vec ) {
vec.push_back(this);
if ( sorter()(t, value) ) {
if (left)
left->find_path(t, vec);
} else if (sorter()(value, t)) {
if (right)
right->find_path(t, vec);
} else {
// found it!
return;
}
}
std::vector< tree_node const* > range_search( T const& left, T const& right )
{
std::vector<tree_node const*> left_path;
std::vector<tree_node const*> right_path;
find_path( left, left_path );
find_path( right, right_path );
// erase common path:
{
auto it1 = left_path.begin();
auto it2 = right_path.begin();
for( ; it1 != left_path.end() && it2 != right_path.end(); ++it1, ++it2) {
if (*it1 != *it2)
{
Debug( "Different: ", printer()( (*it1)->value ), ", ", printer()( (*it2)->value ) );
break;
}
Debug( "Identical: ", printer()( (*it1)->value ), ", ", printer()( (*it2)->value ) );
}
// remove identical prefixes:
if (it2 == right_path.end() && it2 != right_path.begin())
--it2;
if (it1 == left_path.end() && it1 != left_path.begin())
--it1;
right_path.erase( right_path.begin(), it2 );
left_path.erase( left_path.begin(), it1 );
}
for (auto it = left_path.begin(); it != left_path.end(); ++it) {
if (*it && (*it)->right) {
Debug( "Has right child: ", printer()( (*it)->value ) );
*it = (*it)->right.get();
Debug( "It is: ", printer()( (*it)->value ) );
} else {
Debug( "Has no right child: ", printer()( (*it)->value ) );
if ( sorter()( (*it)->value, left) || sorter()( right, (*it)->value) ) {
Debug( printer()( (*it)->value ), "<", printer()( left ), " so erased" );
*it = 0;
}
}
}
for (auto it = right_path.begin(); it != right_path.end(); ++it) {
if (*it && (*it)->left) {
Debug( "Has left child: ", printer()( (*it)->value ) );
*it = (*it)->left.get();
Debug( "It is: ", printer()( (*it)->value ) );
} else {
Debug( "Has no left child: ", printer()( (*it)->value ) );
if ( sorter()( (*it)->value, left) || sorter()( right, (*it)->value) ) {
Debug( printer()( right ), "<", printer()( (*it)->value ), " so erased" );
*it = 0;
}
}
}
left_path.insert( left_path.end(), right_path.begin(), right_path.end() );
// remove duds and duplicates:
auto highwater = std::remove_if( left_path.begin(), left_path.end(), []( tree_node const* n) { return n==0; } );
std::sort( left_path.begin(), highwater );
left_path.erase( std::unique( left_path.begin(), highwater ), left_path.end() );
return left_path;
}
std::unique_ptr<tree_node> left;
std::unique_ptr<tree_node> right;
// rounds down:
template<typename Iterator>
static Iterator middle( Iterator begin, Iterator end ) {
return (end-begin-1)/2 + begin ;
}
template<typename Iterator>
tree_node( Iterator begin, Iterator end ):value(*middle(begin,end)) {
Debug( "Inserted ", get<dim-1>(value), " at level ", dim );
Iterator mid = middle(begin,end);
Assert( begin != end );
if (begin +1 != end) { // not a leaf
Debug( "Not a leaf at level ", dim );
++mid; // so *mid was the last element in the left sub tree
Assert(mid!=begin);
Assert(mid!=end);
left.reset( new tree_node( begin, mid ) );
right.reset( new tree_node( mid, end ) );
} else {
Debug( "Leaf at level ", dim );
}
if (dim > 0) {
subtree.reset( new range_tree<T, dim-1, Order>( begin, end ) );
}
}
};
std::unique_ptr<tree_node> root;
};
// makes the code above a tad easier:
template<typename T, typename Order >
struct range_tree< T, 0, Order > {
typedef typename element_properties<T>::value_type value_type;
struct printer { template<typename Unused>std::string print_elements(Unused const&) {return std::string();} };
range_tree(...) {};
struct tree_node {}; // maybe some stub functions in here
template<size_t n, typename Func>
void walk(Func f) {}
};
int main() {
typedef std::vector<int> vector_type;
std::vector<vector_type> test;
test.push_back( vector_type{5,2} );
test.push_back( vector_type{2,3} );
range_tree< vector_type, 2 > tree( test.begin(), test.end() );
std::cout << "Walking dim 2:";
auto print_node = [](vector_type const& v){ std::cout << "(" << v[0] << "," << v[1] << ")"; };
tree.walk<2>( print_node );
std::cout << "\nWalking dim 1:";
tree.walk<1>( print_node );
std::cout << "\n";
std::cout << "Range search from {3,3} to {10,10}\n";
auto nodes = tree.root->range_search( vector_type{3,3}, vector_type{10,10} );
for (auto it = nodes.begin(); it != nodes.end(); ++it)
{
(*it)->walk<2>( print_node );
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
无效断言(布尔测试){
如果(!测试)
{
标准:不能行走(f);
如果(右)
右->步行(f);
if(子树)
子树->行走(f);
}
void find_path(T const&T,std::vector&vec){
向量推回(这个);
if(分拣机()(t,值)){
如果(左)
左->查找路径(t,vec);
}否则如果(分拣机()(值,t)){
如果(右)
右->查找路径(t,vec);
}否则{
//找到了!
返回;
}
}
标准::向量范围搜索(T const&左,T const&右)
{
std::向量左_路径;
std::向量右路径;
查找路径(左,左路径);
查找路径(右,右路径);
//删除公共路径:
{
auto it1=左_路径。开始();
auto it2=右路径。开始();
对于(;it1!=左路径.end()&&it2!=右路径.end();++it1,++it2){
如果(*it1!=*it2)
{
调试(“不同:”,打印机()((*it1)->值),“,”,打印机()(*it2)->值);
打破
}
调试(“相同:”,打印机()((*it1)->值),“,”,打印机()(*it2)->值);
}
//删除相同的前缀:
if(it2==right\u path.end()&&it2!=right\u path.begin())
--it2;
if(it1==left_path.end()&&it1!=left_path.begin())
--it1;
right_path.erase(right_path.begin(),it2);
left_path.erase(left_path.begin(),it1);
}
对于(自动it=左路径。开始();it!=左路径。结束();++it){
如果(*it&&(*it)->正确){
调试(“具有正确的子项:”,printer()((*it)->value));
*it=(*it)->right.get();
调试(“它是:”,printer()((*It)->value));
}否则{
调试(“没有正确的子项:”,printer()((*it)->value));
if(sorter()((*it)->值,左)| | sorter()(右,(*it)->值)){
Debug(printer()((*it)->value),“嗨,雅克,谢谢你的回答,我正在试图理解你的代码,但我甚至无法编译它:(我试图用VC++和MinGW编译它,但没有骰子。这段代码是用C++0x编写的吗?),有两件事我很困惑,第一件事你为什么要删除相同的前缀?还有range_tree是什么(…){};你什么时候调用它?如果不太需要问,你能解释一下你的代码吗?非常感谢你的时间和努力:)这里的…只是用来丢弃参数。您可能必须用一个包含两个迭代器的不做任何事情的构造函数来替换它。打印和调试代码是C++11,不会在visual studio中编译。删除相同的前缀是查找范围的算法的一部分——Wikipedia对此进行了解释。