I\'m working on this project where I have to search for objects in 3d space, and efficiency is a huge concern, I think Range Tree is perfect for what I\'m tryin
I just read the wikipedia article. Lets see if I can write an n dimensional range tree. Because anything worth doing in 3 dimensions is worth doing in n.
So the basic part of an n-dimensional range tree is that it can be recursively defined in terms of lower dimensional range trees.
Some property classes to work with relatively generic value types. Specialize element_properties
to set the scalar type of whatever your n-dimensional value is, and specialize get(T const&)
to get the i
th dimension of your n-dimensional value.
#include
#include
#include
#include
#include
#include
#include
void Assert(bool test) {
if (!test)
{
std::cout << "Assert failed" << std::endl;
exit(-1);
}
}
template
struct Print {
static void Do(Args... args) {}
};
template
struct Print {
static void Do(Arg arg, Tail... args) {
std::cout << arg;
Print::Do(args...);
}
};
template
void Debug(Args... args) {
std::cout << "DEBUG:[";
Print::Do(args...);
std::cout << "]\n";
}
template
struct element_properties {
typedef typename T::value_type value_type;
};
template<>
struct element_properties {
typedef int value_type;
};
template
typename element_properties::value_type get( T const & t );
template
typename element_properties::value_type get( int i ) { return i; }
template
typename element_properties>::value_type get( std::vector const& v) {
return v[d];
}
template::value_type> >
struct range_tree {
typedef typename element_properties::value_type value_type;
struct sorter {
bool operator()( T const& left, T const& right ) const {
return Order()( get(left), get(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::printer next_printer;
ss << next_printer().print_elements(t);
ss << get(t) << " ";
return ss.str();
}
};
template
range_tree( Iterator begin, Iterator end ) {
std::sort( begin, end, sorter() );
root.reset( new tree_node( begin, end ) );
}
template
void walk(Func f) const {
if (root) root->walk(f);
}
template
void walk(Func f) {
if (root) root->walk(f);
}
struct tree_node {
std::unique_ptr< range_tree > subtree;
T value;
template
void walk(Func f) const {
if (n==dim && !left && !right)
f(value);
if (left)
left->walk(f);
if (right)
right->walk(f);
if (subtree)
subtree->walk(f);
}
template
void walk(Func f) {
if (n==dim && !left && !right)
f(value);
if (left)
left->walk(f);
if (right)
right->walk(f);
if (subtree)
subtree->walk(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 left_path;
std::vector 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 left;
std::unique_ptr right;
// rounds down:
template
static Iterator middle( Iterator begin, Iterator end ) {
return (end-begin-1)/2 + begin ;
}
template
tree_node( Iterator begin, Iterator end ):value(*middle(begin,end)) {
Debug( "Inserted ", get(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( begin, end ) );
}
}
};
std::unique_ptr root;
};
// makes the code above a tad easier:
template
struct range_tree< T, 0, Order > {
typedef typename element_properties::value_type value_type;
struct printer { templatestd::string print_elements(Unused const&) {return std::string();} };
range_tree(...) {};
struct tree_node {}; // maybe some stub functions in here
template
void walk(Func f) {}
};
int main() {
typedef std::vector vector_type;
std::vector 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 );
}
}
which is pretty damn close to an n-dimensional range tree. The 0 dimension tree naturally contains nothing.
Basic facilities to search (in one dimension at a time) have been added now. You can manually do the recursions into lower dimensions, or it up so that the range_search
always returns level 1 tree_node*
s.