⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kdtree.hpp

📁 一个C++写的KdTree容器模板库
💻 HPP
📖 第 1 页 / 共 3 页
字号:
/** \file * Defines the interface for the KDTree class. * * \author Martin F. Krafft <libkdtree@pobox.madduck.net> * * Paul Harris figured this stuff out (below) * Notes: * This is similar to a binary tree, but its not the same. * There are a few important differences: * *  * Each level is sorted by a different criteria (this is fundamental to the design). * *  * It is possible to have children IDENTICAL to its parent in BOTH branches *    This is different to a binary tree, where identical children are always to the right *    So, KDTree has the relationships: *    * The left branch is <= its parent (in binary tree, this relationship is a plain < ) *    * The right branch is <= its parent (same as binary tree) * *    This is done for mostly for performance. *    Its a LOT easier to maintain a consistent tree if we use the <= relationship. *    Note that this relationship only makes a difference when searching for an exact *    item with find() or find_exact, other search, erase and insert functions don't notice *    the difference. * *    In the case of binary trees, you can safely assume that the next identical item *    will be the child leaf, *    but in the case of KDTree, the next identical item might *    be a long way down a subtree, because of the various different sort criteria. * *    So erase()ing a node from a KDTree could require serious and complicated *    tree rebalancing to maintain consistency... IF we required binary-tree-like relationships. * *    This has no effect on insert()s, a < test is good enough to keep consistency. * *    It has an effect on find() searches: *      * Instead of using compare(child,node) for a < relationship and following 1 branch, *        we must use !compare(node,child) for a <= relationship, and test BOTH branches, as *        we could potentially go down both branches. * *    It has no real effect on bounds-based searches (like find_nearest, find_within_range) *    as it compares vs a boundary and would follow both branches if required. * *    This has no real effect on erase()s, a < test is good enough to keep consistency. */#ifndef INCLUDE_KDTREE_KDTREE_HPP#define INCLUDE_KDTREE_KDTREE_HPP#include <vector>#ifdef KDTREE_DEFINE_OSTREAM_OPERATORS#  include <ostream>#  include <stack>#endif#include <cmath>#include <cstddef>#include <cassert>#include <kdtree++/accessor.hpp>#include <kdtree++/allocator.hpp>#include <kdtree++/iterator.hpp>#include <kdtree++/node.hpp>#include <kdtree++/region.hpp>namespace KDTree{#ifdef KDTREE_CHECK_PERFORMANCE   size_t num_dist_calcs = 0;#endif  template <size_t const __K, typename _Val,            typename _Acc = _Bracket_accessor<_Val>,            typename _Cmp = std::less<typename _Acc::result_type>,            typename _Alloc = std::allocator<_Node<_Val> > >    class KDTree : protected _Alloc_base<_Val, _Alloc>    {    protected:      // typedef _Alloc allocator_type;      typedef _Alloc_base<_Val, _Alloc> _Base;      typedef typename _Base::allocator_type allocator_type;      typedef _Node_base* _Base_ptr;      typedef _Node_base const* _Base_const_ptr;      typedef _Node<_Val>* _Link_type;      typedef _Node<_Val> const* _Link_const_type;      typedef _Node_compare<_Val, _Acc, _Cmp> _Node_compare;      typedef _Region<__K, _Val, typename _Acc::result_type, _Acc, _Cmp>        _Region;    public:      typedef _Region Region;      typedef _Val value_type;      typedef value_type* pointer;      typedef value_type const* const_pointer;      typedef value_type& reference;      typedef value_type const& const_reference;      typedef typename _Acc::result_type subvalue_type;      typedef subvalue_type distance_type;   // NEW TYPE - for returning distances      // I wanted to distinguish it from subvaluetype, for the future when/if we have      // types that need a fancy distance calculation.      // This is not complete yet, eg Region still uses subvalue_type for distance_type.      typedef size_t size_type;      typedef ptrdiff_t difference_type;      KDTree( _Acc const& acc = _Acc(), const allocator_type& __a = allocator_type()) throw ()        : _Base(__a), _M_header(_Base::_M_allocate_node()), _M_count(0), _M_acc(acc)      {         _M_empty_initialise();      }      KDTree(const KDTree& __x) throw ()         : _Base(__x.get_allocator()), _M_header(_Base::_M_allocate_node()), _M_count(0), _M_acc(__x._M_acc)      {         _M_empty_initialise();         this->insert(begin(), __x.begin(), __x.end());         this->optimise();      }      template<typename _InputIterator>        KDTree(_InputIterator __first, _InputIterator __last,             _Acc const& acc = _Acc(), const allocator_type& __a = allocator_type()) throw ()        : _Base(__a), _M_header(_Base::_M_allocate_node()), _M_count(0), _M_acc(acc)      {         _M_empty_initialise();         this->insert(begin(), __first, __last);         this->optimise();      }      KDTree&      operator=(const KDTree& __x)      {         if (this != &__x)         {            this->clear();            this->insert(begin(),__x.begin(),__x.end());            this->optimize();         }         return *this;      }      ~KDTree() throw ()      {        this->clear();        _M_deallocate_node(_M_header);      }      allocator_type      get_allocator() const      {        return _Base::get_allocator();      }      size_type      size() const      {        return _M_count;      }      size_type      max_size() const      {        return size_type(-1);      }      bool      empty() const      {        return this->size() == 0;      }      void      clear()      {        _M_erase_subtree(_M_get_root());        _M_set_leftmost(_M_header);        _M_set_rightmost(_M_header);        _M_set_root(NULL);        _M_count = 0;      }      // typedef _Iterator<_Val, reference, pointer> iterator;      typedef _Iterator<_Val, const_reference, const_pointer> const_iterator;      // No mutable iterator at this stage      typedef const_iterator iterator;      typedef std::reverse_iterator<const_iterator> const_reverse_iterator;      typedef std::reverse_iterator<iterator> reverse_iterator;      const_iterator begin() const { return const_iterator(_M_get_leftmost()); }      const_iterator end() const { return const_iterator(_M_header); }      const_reverse_iterator rbegin() const { return const_reverse_iterator(_M_get_rightmost()); }      const_reverse_iterator rend() const { return const_reverse_iterator(_M_header); }      // iterator begin() { return iterator(_M_get_leftmost()); }      // iterator end() { return iterator(_M_header); }      // reverse_iterator rbegin() { return reverse_iterator(end()); }      // reverse_iterator rend() { return reverse_iterator(begin()); }      iterator      insert(iterator /* ignored */, const_reference __V) throw (std::bad_alloc)      {         return this->insert(__V);      }      iterator      insert(const_reference __V) throw (std::bad_alloc)      {        if (!_M_get_root())          {            _Link_type __n = _M_new_node(__V, _M_header);            ++_M_count;            _M_set_root(__n);            _M_set_leftmost(__n);            _M_set_rightmost(__n);            return iterator(__n);          }        return _M_insert(_M_get_root(), __V, 0);      }      template <class _InputIterator>      void insert(_InputIterator __first, _InputIterator __last) {         for (; __first != __last; ++__first)            this->insert(*__first);      }      void      insert(iterator __pos, size_type __n, const value_type& __x)      {        for (; __n > 0; --__n)          this->insert(__pos, __x);      }      template<typename _InputIterator>      void      insert(iterator __pos, _InputIterator __first, _InputIterator __last) {         for (; __first != __last; ++__first)            this->insert(__pos, *__first);      }      // Note: this uses the find() to location the item you want to erase.      // find() compares by equivalence of location ONLY.  See the comments      // above find_exact() for why you may not want this.      //      // If you want to erase ANY item that has the same location as __V,      // then use this function.      //      // If you want to erase a PARTICULAR item, and not any other item      // that might happen to have the same location, then you should use      // erase_exact().      void      erase(const_reference __V) throw () {        this->erase(this->find(__V));      }      void      erase_exact(const_reference __V) throw () {        this->erase(this->find_exact(__V));      }      // note: kept as const because its easier to const-cast it away      void      erase(const_iterator const& __IT) throw ()      {         assert(__IT != this->end());        _Link_const_type target = static_cast<_Link_const_type>(__IT._M_node);        _Link_const_type n = target;        size_t level = 0;        while ((n = _S_parent(n)) != _M_header)           ++level;        _M_erase( const_cast<_Link_type>(target), level );        _M_delete_node( const_cast<_Link_type>(target) );        --_M_count;      }/* this does not work since erasure changes sort order      void      erase(const_iterator __A, const_iterator const& __B) throw ()      {        if (0 && __A == this->begin() && __B == this->end())          {            this->clear();          }        else          {            while (__A != __B)              this->erase(__A++);          }      }*/      // compares via equivalence      // so if you are looking for any item with the same location,      // according to the standard accessor comparisions,      // then this is the function for you.      const_iterator      find(const_reference __V) const throw ()      {        if (!_M_get_root()) return this->end();        return _M_find(_M_get_root(), __V, 0);      }      // compares via equality      // if you are looking for a particular item in the tree,      // and (for example) it has an ID that is checked via an == comparison      // eg      // struct Item      // {      //    unsigned int unique_id;      //    bool operator==(Item const& a, Item const& b) { return a.unique_id == b.unique_id; }      //    Location location;      // };      // Two items may be equivalent in location.  find() would return      // either one of them.  But no two items have the same ID, so      // find_exact() would always return the item with the same location AND id.      //      const_iterator      find_exact(const_reference __V) const throw ()      {        if (!_M_get_root()) return this->end();        return _M_find_exact(_M_get_root(), __V, 0);      }      size_t        count_within_range(const_reference __V, subvalue_type const __R) const throw ()        {          if (!_M_get_root()) return 0;          _Region __region(_M_acc,__V,__R);          return this->count_within_range(__region);        }      size_t        count_within_range(_Region const& __REGION) const throw ()        {          if (!_M_get_root()) return 0;          _Region __bounds(__REGION);          return _M_count_within_range(_M_get_root(),                               __REGION, __bounds, 0);        }      template <typename SearchVal, class Visitor>        Visitor        visit_within_range(SearchVal V, subvalue_type const R, Visitor visitor) const throw ()        {          if (!_M_get_root()) return visitor;          _Region region(_M_acc,V,R);          return this->visit_within_range(region, visitor);        }      template <class Visitor>        Visitor        visit_within_range(_Region const& REGION, Visitor visitor) const throw ()        {          if (_M_get_root())            {              _Region bounds(REGION);              return _M_visit_within_range(visitor, _M_get_root(), REGION, bounds, 0);            }          return visitor;        }      template <typename SearchVal, typename _OutputIterator>        _OutputIterator        find_within_range(SearchVal __V, subvalue_type const __R,                          _OutputIterator __out) const throw ()        {          if (!_M_get_root()) return __out;          _Region __region(_M_acc,__V,__R);          return this->find_within_range(__region, __out);        }      template <typename _OutputIterator>        _OutputIterator        find_within_range(_Region const& __REGION,                          _OutputIterator __out) const throw ()        {          if (_M_get_root())            {              _Region __bounds(__REGION);              __out = _M_find_within_range(__out, _M_get_root(),                                   __REGION, __bounds, 0);            }          return __out;        }      template <typename SearchVal>         std::pair<const_iterator,distance_type>        find_nearest(SearchVal __V, subvalue_type const __Max_R ) const throw ()        {          if (!_M_get_root())             return std::pair<const_iterator,distance_type>(this->end(),__Max_R);          _Region __region(_M_acc,__V);  // note: zero-area!

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -