Spatial C++ Library
Generic Multi-Dimensional Containers and Spatial Operations
spatial_kdtree.hpp
1 // -*- C++ -*-
2 //
3 // Copyright Sylvain Bougerel 2009 - 2013.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file COPYING or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
20 #ifndef SPATIAL_KDTREE_HPP
21 #define SPATIAL_KDTREE_HPP
22 
23 #include <algorithm> // for std::equal and std::lexicographical_compare
24 #include <vector>
25 
26 #include "spatial_ordered.hpp"
27 #include "spatial_mapping.hpp"
28 #include "spatial_equal.hpp"
29 #include "spatial_compress.hpp"
30 #include "spatial_value_compare.hpp"
31 #include "spatial_template_member_swap.hpp"
32 #include "spatial_assert.hpp"
33 #include "spatial_except.hpp"
34 
35 namespace spatial
36 {
37  namespace details
38  {
48  template <typename Rank, typename Key, typename Value, typename Compare,
49  typename Alloc>
50  class Kdtree
51  {
53 
54  public:
55  // Container intrincsic types
56  typedef Rank rank_type;
57  typedef typename mutate<Key>::type key_type;
58  typedef typename mutate<Value>::type value_type;
59  typedef Compare key_compare;
61  typedef Alloc allocator_type;
63 
64  // Container iterator related types
65  typedef Value* pointer;
66  typedef const Value* const_pointer;
67  typedef Value& reference;
68  typedef const Value& const_reference;
69  typedef std::size_t size_type;
70  typedef std::ptrdiff_t difference_type;
71 
72  // Container iterators
73  // Conformant to C++ ISO standard, if Key and Value are the same type then
74  // iterator and const_iterator shall be the same.
77  typedef std::reverse_iterator<iterator> reverse_iterator;
78  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
79 
80  private:
81  typedef typename Alloc::template rebind
83  typedef typename Alloc::template rebind
84  <value_type>::other Value_allocator;
85 
86  // The types used to deal with nodes
87  typedef typename mode_type::node_ptr node_ptr;
89  typedef typename mode_type::link_ptr link_ptr;
91 
92  private:
101  struct Implementation : Rank
102  {
103  Implementation(const rank_type& rank, const key_compare& compare,
104  const Link_allocator& alloc)
105  : Rank(rank), _count(compare, 0), _header(alloc) { initialize(); }
106 
108  : Rank(impl), _count(impl._count.base(), 0),
109  _header(impl._header.base()) { initialize(); }
110 
111  void initialize()
112  {
113  _header().parent = &_header();
114  _header().left = &_header(); // the end marker, *must* not change!
115  _header().right = &_header();
116  _leftmost = &_header(); // the substitute left most pointer
117  }
118 
122  } _impl;
123 
124  private:
125  struct Maximum : key_compare
126  {
127  Maximum(const key_compare& key_comp, node_ptr node_)
128  : key_compare(key_comp), node(node_) { }
129  key_compare comp() const
130  { return static_cast<key_compare>(*this); }
131  node_ptr node;
132  };
133 
134  private:
135  // Internal accessors
136  node_ptr get_header()
137  { return static_cast<node_ptr>(&_impl._header()); }
138 
139  const_node_ptr get_header() const
140  { return static_cast<const_node_ptr>(&_impl._header()); }
141 
142  node_ptr get_leftmost()
143  { return _impl._leftmost; }
144 
145  const_node_ptr get_leftmost() const
146  { return _impl._leftmost; }
147 
148  void set_leftmost(node_ptr x)
149  { _impl._leftmost = x; }
150 
151  node_ptr get_rightmost()
152  { return _impl._header().right; }
153 
154  const_node_ptr get_rightmost() const
155  { return _impl._header().right; }
156 
157  void set_rightmost(node_ptr x)
158  { _impl._header().right = x; }
159 
160  node_ptr get_root()
161  { return _impl._header().parent; }
162 
163  const_node_ptr get_root() const
164  { return _impl._header().parent; }
165 
166  void set_root(node_ptr x)
167  { _impl._header().parent = x; }
168 
169  rank_type& get_rank()
170  { return *static_cast<Rank*>(&_impl); }
171 
172  key_compare& get_compare()
173  { return _impl._count.base(); }
174 
175  Link_allocator& get_link_allocator()
176  { return _impl._header.base(); }
177 
178  Value_allocator get_value_allocator() const
179  { return _impl._header.base(); }
180 
181  private:
182  // Allocation/Deallocation of nodes
183  struct safe_allocator // RAII for exception-safe memory management
184  {
185  Link_allocator* alloc;
186  link_ptr link;
187  safe_allocator(Link_allocator& a)
188  : alloc(&a), link(0)
189  { link = alloc->allocate(1); } // may throw
190  ~safe_allocator() { if (link) { alloc->deallocate(link, 1); } }
191  link_ptr release() { link_ptr p = link; link=0; return p; }
192  };
193 
194  node_ptr
195  create_node(const value_type& value)
196  {
197  safe_allocator safe(get_link_allocator());
198  // the following may throw but we have RAII on safe_allocator
199  get_value_allocator().construct(mutate_pointer(&safe.link->value),
200  value);
201  link_ptr node = safe.release();
202  // leave parent uninitialized: its value will change during insertion.
203  node->left = 0;
204  node->right = 0;
205  return node; // silently casts into the parent node pointer
206  }
207 
211  void
212  destroy_node(node_ptr node)
213  {
214  get_value_allocator().destroy(mutate_pointer(&value(node)));
215  get_link_allocator().deallocate(link(node), 1);
216  }
217 
221  void
223 
224  private:
228  iterator insert_node(node_ptr target_node);
229 
237  node_ptr rebalance_node_insert
238  (typename std::vector<node_ptr>::iterator first,
239  typename std::vector<node_ptr>::iterator last, dimension_type dim,
240  node_ptr header);
241 
247  typename std::vector<node_ptr>::iterator
248  median
249  (typename std::vector<node_ptr>::iterator first,
250  typename std::vector<node_ptr>::iterator last, dimension_type dim);
251 
259  void copy_structure(const Self& other);
260 
266  void copy_rebalance(const Self& other);
267 
273  node_ptr erase_node(dimension_type node_dim, node_ptr node);
274 
275  public:
276  // Iterators standard interface
277  iterator begin()
278  { iterator it; it.node = get_leftmost(); return it; }
279 
280  const_iterator begin() const
281  { const_iterator it; it.node = get_leftmost(); return it; }
282 
283  const_iterator cbegin() const { return begin(); }
284 
285  iterator end()
286  { return iterator(get_header()); }
287 
288  const_iterator end() const
289  { return const_iterator(get_header()); }
290 
291  const_iterator cend() const { return end(); }
292 
293  reverse_iterator rbegin()
294  { return reverse_iterator(end()); }
295 
296  const_reverse_iterator rbegin() const
297  { return const_reverse_iterator(end()); }
298 
299  const_reverse_iterator crbegin() const
300  { return rbegin(); }
301 
302  reverse_iterator rend()
303  { return reverse_iterator(begin()); }
304 
305  const_reverse_iterator rend() const
306  { return const_reverse_iterator(begin()); }
307 
308  const_reverse_iterator crend() const
309  { return rend(); }
310 
311  public:
315  rank_type rank() const
316  { return *static_cast<const Rank*>(&_impl); }
317 
322  { return rank()(); }
323 
327  key_compare key_comp() const
328  { return _impl._count.base(); }
329 
333  value_compare value_comp() const
334  { return value_compare(_impl._count.base()); }
335 
339  allocator_type
340  get_allocator() const { return get_value_allocator(); }
341 
345  bool empty() const { return (get_header() == get_root()); }
346 
350  size_type size() const { return _impl._count(); }
351 
356  size_type count() const { return _impl._count(); }
357 
361  void clear()
363 
367  size_type max_size() const
368  { return _impl._header.base().max_size(); }
369 
370  public:
372  : _impl(rank_type(), key_compare(), allocator_type())
373  { }
374 
375  explicit Kdtree(const rank_type& rank_)
376  : _impl(rank_, key_compare(), allocator_type())
377  { }
378 
379  explicit Kdtree(const key_compare& compare_)
380  : _impl(rank_type(), compare_, allocator_type())
381  { }
382 
383  Kdtree(const rank_type& rank_, const key_compare& compare_)
384  : _impl(rank_, compare_, allocator_type())
385  { }
386 
387  Kdtree(const rank_type& rank_, const key_compare& compare_,
388  const allocator_type& allocator_)
389  : _impl(rank_, compare_, allocator_)
390  { }
391 
403  Kdtree(const Self& other, bool balancing = false) : _impl(other._impl)
404  {
405  if (!other.empty())
406  {
407  if (balancing) { copy_rebalance(other); }
408  else { copy_structure(other); }
409  }
410  }
411 
420  Self&
421  operator=(const Self& other)
422  {
423  if (&other != this)
424  {
427  ::do_it(get_rank(), other.rank());
429  ::do_it(get_compare(), other.key_comp());
430  _impl.initialize();
431  if (!other.empty()) { copy_structure(other); }
432  else _impl._count() = 0;
433  }
434  return *this;
435  }
436 
441  { destroy_all_nodes(); }
442 
443  public:
451  void
452  swap(Self& other)
453  {
454  if (empty() && other.empty()) return;
456  (get_rank(), other.get_rank());
458  (get_compare(), other.get_compare());
461  if (_impl._header().parent == &_impl._header())
462  {
463  _impl._header().parent = &other._impl._header();
464  _impl._header().right = &other._impl._header();
465  _impl._leftmost = &other._impl._header();
466  }
467  else if (other._impl._header().parent == &other._impl._header())
468  {
469  other._impl._header().parent = &_impl._header();
470  other._impl._header().right = &_impl._header();
471  other._impl._leftmost = &_impl._header();
472  }
473  std::swap(_impl._header().parent, other._impl._header().parent);
474  std::swap(_impl._header().right, other._impl._header().right);
475  std::swap(_impl._leftmost, other._impl._leftmost);
476  if (_impl._header().parent != &_impl._header())
477  { _impl._header().parent->parent = &_impl._header(); }
478  if (other._impl._header().parent != &other._impl._header())
479  { other._impl._header().parent->parent = &other._impl._header(); }
480  std::swap(_impl._count(), other._impl._count());
481  }
482 
483  // Mutable functions
497  void rebalance();
498 
502  iterator
503  insert(const value_type& value)
504  {
505  return insert_node(create_node(value));
506  }
507 
514  template<typename InputIterator>
515  void
516  insert(InputIterator first, InputIterator last)
517  { for (; first != last; ++first) { insert(*first); } }
518 
527  template<typename InputIterator>
528  void
529  insert_rebalance(InputIterator first, InputIterator last);
530 
532 
549  iterator
550  find(const key_type& key)
551  {
552  if (empty()) return end();
553  return iterator(preorder_first(get_root(), 0, rank(),
555  .first);
556  }
557 
558  const_iterator
559  find(const key_type& key) const
560  {
561  if (empty()) return end();
564  (key_comp(), key))
565  .first);
566  }
568 
575  void
576  erase(iterator pointer);
577 
585  size_type
586  erase(const key_type& value);
587  };
588 
592  template <typename Rank, typename Key, typename Value, typename Compare,
593  typename Alloc>
594  inline void swap
597  { left.swap(right); }
598 
611  template <typename Rank, typename Key, typename Value, typename Compare,
613  typename Alloc>
614  inline bool
617  {
618  return lhs.size() == rhs.size()
619  && std::equal(ordered_begin(lhs), ordered_end(lhs),
620  ordered_begin(rhs));
621  }
622 
623  template <typename Rank, typename Key, typename Value, typename Compare,
624  typename Alloc>
625  inline bool
628  { return !(lhs == rhs); }
630 
643  template <typename Rank, typename Key, typename Value, typename Compare,
645  typename Alloc>
646  inline bool
647  operator<(const Kdtree<Rank, Key, Value, Compare, Alloc>& lhs,
649  {
650  return std::lexicographical_compare
651  (ordered_begin(lhs), ordered_end(lhs),
652  ordered_begin(rhs), ordered_end(rhs));
653  }
654 
655  template <typename Rank, typename Key, typename Value, typename Compare,
656  typename Alloc>
657  inline bool
660  { return rhs < lhs; }
661 
662  template <typename Rank, typename Key, typename Value, typename Compare,
663  typename Alloc>
664  inline bool
665  operator<=(const Kdtree<Rank, Key, Value, Compare, Alloc>& lhs,
667  { return !(rhs < lhs); }
668 
669  template <typename Rank, typename Key, typename Value, typename Compare,
670  typename Alloc>
671  inline bool
674  { return !(lhs < rhs); }
676 
677  template <typename Rank, typename Key, typename Value, typename Compare,
678  typename Alloc>
679  inline void
680  Kdtree<Rank, Key, Value, Compare, Alloc>
681  ::destroy_all_nodes()
682  {
683  node_ptr node = get_root();
684  while (!header(node))
685  {
686  if (node->left != 0) { node = node->left; }
687  else if (node->right != 0) { node = node->right; }
688  else
689  {
690  node_ptr p = node->parent;
691  if (header(p))
692  {
693  set_root(get_header());
694  set_leftmost(get_header());
695  set_rightmost(get_header());
696  }
697  else
698  {
699  if (p->left == node) { p->left = 0; }
700  else { p->right = 0; }
701  }
702  SPATIAL_ASSERT_CHECK(node != 0);
703  SPATIAL_ASSERT_CHECK(p != 0);
704  destroy_node(node);
705  node = p;
706  }
707  }
708  }
709 
710  template <typename Rank, typename Key, typename Value, typename Compare,
711  typename Alloc>
712  inline
715  (typename mode_type::node_ptr target_node)
716  {
717  SPATIAL_ASSERT_CHECK(target_node != 0);
718  SPATIAL_ASSERT_CHECK(target_node->right == 0);
719  SPATIAL_ASSERT_CHECK(target_node->left == 0);
720  node_ptr node = get_root();
721  dimension_type node_dim = 0;
722  if (header(node))
723  {
724  SPATIAL_ASSERT_CHECK(_impl._count() == 0);
725  target_node->parent = get_header();
726  set_root(target_node);
727  set_leftmost(target_node);
728  set_rightmost(target_node);
729  ++_impl._count();
730  }
731  else
732  {
733  while (true)
734  {
735  if (key_comp()(node_dim,
736  const_key(target_node), const_key(node)))
737  {
738  if (node->left != 0)
739  {
740  node = node->left;
741  node_dim = incr_dim(rank(), node_dim);
742  }
743  else
744  {
745  node->left = target_node;
746  target_node->parent = node;
747  if (node == get_leftmost()) { set_leftmost(target_node); }
748  ++_impl._count();
749  break;
750  }
751  }
752  else
753  {
754  if (node->right != 0)
755  {
756  node = node->right;
757  node_dim = incr_dim(rank(), node_dim);
758  }
759  else
760  {
761  node->right = target_node;
762  target_node->parent = node;
763  if (node == get_rightmost())
764  { set_rightmost(target_node); }
765  ++_impl._count();
766  break;
767  }
768  }
769  }
770  }
771  SPATIAL_ASSERT_CHECK(empty() == false);
772  SPATIAL_ASSERT_CHECK(_impl._count() != 0);
773  SPATIAL_ASSERT_CHECK(target_node->right == 0);
774  SPATIAL_ASSERT_CHECK(target_node->left == 0);
775  SPATIAL_ASSERT_CHECK(target_node->parent != 0);
776  SPATIAL_ASSERT_INVARIANT(*this);
777  return iterator(target_node);
778  }
779 
780  template <typename Rank, typename Key, typename Value, typename Compare,
781  typename Alloc>
782  inline void
784  (const Self& other)
785  {
786  SPATIAL_ASSERT_CHECK(!other.empty());
787  SPATIAL_ASSERT_CHECK(empty());
788  const_node_ptr other_node = other.get_root();
789  node_ptr node = create_node(const_value(other_node)); // may throw
790  node->parent = get_header();
791  set_root(node);
792  try
793  {
794  while(!header(other_node))
795  {
796  if (other_node->left != 0)
797  {
798  other_node = other_node->left;
799  node_ptr target = create_node(const_value(other_node));
800  target->parent = node;
801  target->left = target->right = 0;
802  node->left = target;
803  node = node->left;
804  }
805  else if (other_node->right != 0)
806  {
807  other_node = other_node->right;
808  node_ptr target = create_node(const_value(other_node));
809  target->parent = node;
810  target->right = target->left = 0;
811  node->right = target;
812  node = node->right;
813  }
814  else
815  {
816  const_node_ptr p = other_node->parent;
817  while (!header(p) && (other_node == p->right || p->right == 0))
818  {
819  other_node = p;
820  node = node->parent;
821  p = other_node->parent;
822  }
823  other_node = p;
824  node = node->parent;
825  if (!header(p))
826  {
827  other_node = other_node->right;
828  node_ptr target = create_node(const_value(other_node));
829  target->parent = node;
830  target->right = target->left = 0;
831  node->right = target;
832  node = node->right;
833  }
834  }
835  }
836  SPATIAL_ASSERT_CHECK(!empty());
837  SPATIAL_ASSERT_CHECK(header(other_node));
838  SPATIAL_ASSERT_CHECK(header(node));
839  }
840  catch (...)
841  { clear(); throw; } // clean-up before re-throw
842  set_leftmost(minimum(get_root()));
843  set_rightmost(maximum(get_root()));
844  _impl._count() = other.size();
845  SPATIAL_ASSERT_CHECK(size() != 0);
846  SPATIAL_ASSERT_CHECK(size() == other.size());
847  SPATIAL_ASSERT_INVARIANT(*this);
848  }
849 
850  template <typename Rank, typename Key, typename Value, typename Compare,
851  typename Alloc>
852  inline void
854  ::copy_rebalance(const Self& other)
855  {
856  SPATIAL_ASSERT_CHECK(empty());
857  SPATIAL_ASSERT_CHECK(!other.empty());
858  std::vector<node_ptr> ptr_store;
859  ptr_store.reserve(other.size()); // may throw
860  try
861  {
862  for(const_iterator i = other.begin(); i != other.end(); ++i)
863  { ptr_store.push_back(create_node(*i)); } // may throw
864  }
865  catch (...)
866  {
867  for(typename std::vector<node_ptr>::iterator i = ptr_store.begin();
868  i != ptr_store.end(); ++i)
869  { destroy_node(*i); }
870  throw;
871  }
872  set_root(rebalance_node_insert(ptr_store.begin(), ptr_store.end(), 0,
873  get_header()));
874  node_ptr root = get_root();
875  while (root->left != 0) root = root->left;
876  set_leftmost(root);
877  root = get_root();
878  while (root->right != 0) root = root->right;
879  set_rightmost(root);
880  _impl._count() = other.size();
881  SPATIAL_ASSERT_CHECK(!empty());
882  SPATIAL_ASSERT_CHECK(size() != 0);
883  SPATIAL_ASSERT_INVARIANT(*this);
884  }
885 
886  template <typename InputIterator>
887  inline std::ptrdiff_t
889  (InputIterator first, InputIterator last, std::random_access_iterator_tag)
890  { return last - first; }
891 
892  template <typename InputIterator>
893  inline std::ptrdiff_t
895  (InputIterator, InputIterator, std::input_iterator_tag)
896  { return 0; }
897 
898  template <typename Rank, typename Key, typename Value, typename Compare,
899  typename Alloc>
900  template <typename InputIterator>
901  inline void
902  Kdtree<Rank, Key, Value, Compare, Alloc>
903  ::insert_rebalance(InputIterator first, InputIterator last)
904  {
905  if (first == last && empty()) return;
906  std::vector<node_ptr> ptr_store;
907  ptr_store.reserve // may throw
908  (size()
910  (first, last,
911  typename std::iterator_traits<InputIterator>::iterator_category()));
912  try
913  {
914  for(InputIterator i = first; i != last; ++i)
915  { ptr_store.push_back(create_node(*i)); } // may throw
916  }
917  catch (...)
918  {
919  for(typename std::vector<node_ptr>::iterator i = ptr_store.begin();
920  i != ptr_store.end(); ++i)
921  { destroy_node(*i); }
922  throw;
923  }
924  for(iterator i = begin(); i != end(); ++i)
925  { ptr_store.push_back(i.node); }
926  set_root(rebalance_node_insert(ptr_store.begin(), ptr_store.end(), 0,
927  get_header()));
928  node_ptr root = get_root();
929  while (root->left != 0) root = root->left;
930  set_leftmost(root);
931  root = get_root();
932  while (root->right != 0) root = root->right;
933  set_rightmost(root);
934  _impl._count() = ptr_store.size();
935  SPATIAL_ASSERT_CHECK(!empty());
936  SPATIAL_ASSERT_CHECK(size() != 0);
937  SPATIAL_ASSERT_INVARIANT(*this);
938  }
939 
940  template <typename Rank, typename Key, typename Value, typename Compare,
941  typename Alloc>
942  inline void
944  {
945  if (empty()) return;
946  std::vector<node_ptr> ptr_store;
947  ptr_store.reserve(size()); // may throw
948  for(iterator i = begin(); i != end(); ++i)
949  { ptr_store.push_back(i.node); }
950  set_root(rebalance_node_insert(ptr_store.begin(), ptr_store.end(), 0,
951  get_header()));
952  node_ptr node = get_root();
953  while (node->left != 0) node = node->left;
954  set_leftmost(node);
955  node = get_root();
956  while (node->right != 0) node = node->right;
957  set_rightmost(node);
958  SPATIAL_ASSERT_CHECK(!empty());
959  SPATIAL_ASSERT_CHECK(size() != 0);
960  SPATIAL_ASSERT_INVARIANT(*this);
961  }
962 
963  template<typename Compare, typename Node_ptr>
965  {
966  Compare compare;
968 
969  mapping_compare(const Compare& c, dimension_type d)
970  : compare(c), dimension(d) { }
971 
972  bool
973  operator() (const Node_ptr& x, const Node_ptr& y) const
974  {
975  return compare(dimension, const_key(x), const_key(y));
976  }
977  };
978 
979  template <typename Rank, typename Key, typename Value, typename Compare,
980  typename Alloc>
981  inline typename
982  std::vector<typename Kdtree<Rank, Key, Value, Compare, Alloc>::node_ptr>
983  ::iterator
985  (typename std::vector<node_ptr>::iterator first,
986  typename std::vector<node_ptr>::iterator last,
987  dimension_type dim)
988  {
989  SPATIAL_ASSERT_CHECK(first != last);
990  mapping_compare<Compare, node_ptr> less(key_comp(), dim);
991  // Memory ordering varies between machines, so we use '/ 2' and not '>> 1'
992  if (first == (last - 1)) return first;
993  typename std::vector<node_ptr>::iterator mid = first + (last - first) / 2;
994  std::nth_element(first, mid, last, less);
995  typename std::vector<node_ptr>::iterator seek = mid;
996  typename std::vector<node_ptr>::iterator pivot = mid;
997  do
998  {
999  --seek;
1000  SPATIAL_ASSERT_CHECK(!less(*mid, *seek));
1001  if (!less(*seek, *mid))
1002  {
1003  --pivot;
1004  if (seek != pivot) { std::swap(*seek, *pivot); }
1005  // pivot and mid are equal at this point:
1006  SPATIAL_ASSERT_CHECK(!less(*pivot, *mid) && !less(*mid, *pivot));
1007  }
1008  }
1009  while (seek != first);
1010  SPATIAL_ASSERT_CHECK(pivot != last);
1011  return pivot;
1012  }
1013 
1014  template <typename Rank, typename Key, typename Value, typename Compare,
1015  typename Alloc>
1019  (typename std::vector<node_ptr>::iterator first,
1020  typename std::vector<node_ptr>::iterator last,
1021  dimension_type dim, node_ptr parent)
1022  {
1023  SPATIAL_ASSERT_CHECK(first != last);
1024  SPATIAL_ASSERT_CHECK(dim < dimension());
1025  typename std::vector<node_ptr>::iterator med
1026  = median(first, last, dim);
1027  node_ptr root = *med;
1028  root->parent = parent;
1029  dim = incr_dim(rank(), dim);
1030  if (med + 1 != last)
1031  { root->right = rebalance_node_insert(med + 1, last, dim, root); }
1032  else root->right = 0;
1033  last = med;
1034  parent = root;
1035  while(first != last)
1036  {
1037  med = median(first, last, dim);
1038  node_ptr node = *med;
1039  parent->left = node;
1040  node->parent = parent;
1041  dim = incr_dim(rank(), dim);
1042  if (med + 1 != last)
1043  { node->right = rebalance_node_insert(med + 1, last, dim, node); }
1044  else node->right = 0;
1045  last = med;
1046  parent = node;
1047  }
1048  parent->left = 0;
1049  SPATIAL_ASSERT_CHECK(parent->left == 0);
1050  SPATIAL_ASSERT_CHECK(root->parent != root);
1051  return root;
1052  }
1053 
1054  template <typename Rank, typename Key, typename Value, typename Compare,
1055  typename Alloc>
1058  (dimension_type node_dim, node_ptr node)
1059  {
1060  SPATIAL_ASSERT_CHECK(node != 0);
1061  SPATIAL_ASSERT_CHECK(!header(node));
1062  node_ptr first_swap = 0;
1063  while (node->right != 0 || node->left != 0)
1064  {
1065  // If there is nothing on the right, to preserve the invariant, we
1066  // need to shift the whole sub-tree to the right. This K-d tree
1067  // rotation is not documented anywhere I've searched. The previous
1068  // known rotation by J. L. Bentely for erasing nodes in the K-d tree
1069  // is incorrect for strict invariant (left nodes strictly less than
1070  // root node). This could explain while it is hard to find an
1071  // implementation of K-d Tree with the O(log(n)) erase function
1072  // predicted in his paper.
1073  if (node->right == 0)
1074  {
1075  node->right = node->left;
1076  node->left = 0;
1077  if (get_rightmost() == node)
1078  { set_rightmost(maximum(node->right)); }
1079  const_node_ptr seeker = node->right;
1080  if (get_leftmost() == seeker) { set_leftmost(node); }
1081  else
1082  {
1083  while (seeker->left != 0)
1084  {
1085  seeker = seeker->left;
1086  if (get_leftmost() == seeker)
1087  { set_leftmost(node); break; }
1088  }
1089  }
1090  }
1091  std::pair<node_ptr, dimension_type> candidate
1092  = minimum_mapping(node->right, incr_dim(rank(), node_dim),
1093  rank(), node_dim, key_comp());
1094  if (get_rightmost() == candidate.first)
1095  { set_rightmost(node); }
1096  if (get_leftmost() == node)
1097  { set_leftmost(candidate.first); }
1098  if (first_swap == 0)
1099  { first_swap = candidate.first; }
1100  swap_node(candidate.first, node);
1101  node = candidate.first;
1102  node_dim = candidate.second;
1103  }
1104  SPATIAL_ASSERT_CHECK(node != 0);
1105  SPATIAL_ASSERT_CHECK(node->right == 0);
1106  SPATIAL_ASSERT_CHECK(node->left == 0);
1107  SPATIAL_ASSERT_CHECK(node->parent != 0);
1108  node_ptr p = node->parent;
1109  if (header(p))
1110  {
1111  SPATIAL_ASSERT_CHECK(count() == 1);
1112  set_root(get_header());
1113  set_leftmost(get_header());
1114  set_rightmost(get_header());
1115  }
1116  else if (p->left == node)
1117  {
1118  p->left = 0;
1119  if (get_leftmost() == node) { set_leftmost(p); }
1120  }
1121  else
1122  {
1123  p->right = 0;
1124  if (get_rightmost() == node) { set_rightmost(p); }
1125  }
1126  --_impl._count();
1127  SPATIAL_ASSERT_CHECK((get_header() == get_root())
1128  ? (_impl._count() == 0) : true);
1129  destroy_node(node);
1130  SPATIAL_ASSERT_INVARIANT(*this);
1131  return first_swap;
1132  }
1133 
1134  template <typename Rank, typename Key, typename Value, typename Compare,
1135  typename Alloc>
1136  inline void
1139  {
1141  node_ptr node = target.node;
1142  dimension_type node_dim = rank()() - 1;
1143  while(!header(node))
1144  {
1145  node_dim = details::incr_dim(rank(), node_dim);
1146  node = node->parent;
1147  }
1148  except::check_iterator(node, get_header());
1149  erase_node(node_dim, target.node);
1150  }
1151 
1152  template <typename Rank, typename Key, typename Value, typename Compare,
1153  typename Alloc>
1154  inline
1157  (const key_type& key)
1158  {
1159  if (empty()) return 0;
1160  node_ptr node = get_root();
1161  dimension_type dim;
1162  details::Equal<Self> equal_query(key_comp(), key);
1163  details::assign(node, dim,
1164  preorder_first(node, 0, rank(), equal_query));
1165  if (header(node)) return 0;
1166  size_type cnt = 0;
1167  for (;;)
1168  {
1169  node_ptr tmp = erase_node(dim, node);
1170  ++cnt;
1171  if (tmp == 0) break; // no further node to erase for sure!
1172  details::assign(node, dim,
1173  preorder_first(tmp, dim, rank(), equal_query));
1174  if (tmp->parent == node) break; // no more match
1175  }
1176  return cnt;
1177  }
1178 
1179  } // namespace details
1180 } // namespace spatial
1181 
1182 #endif // SPATIAL_KDTREE_HPP
mutate< Key >::type key_type
~Kdtree()
Deallocate all nodes in the destructor.
Compress< Link_allocator, Node< mode_type > > _header
void rebalance()
Rebalance the k-d tree near-optimally, resulting in order of complexity on most search functions...
Const_node_iterator< mode_type > const_iterator
const_reverse_iterator rend() const
A bidirectional iterator traversing all node in the tree in inorder traversal.
A bidirectional iterator traversing all node in the tree in inorder traversal.
Implementation(const Implementation &impl)
Alloc::template rebind< Kdtree_link< Key, Value > >::other Link_allocator
Kdtree(const key_compare &compare_)
iterator insert_node(node_ptr target_node)
Insert a node already allocated into the tree.
mutate< Value >::type value_type
const_iterator cbegin() const
mode_type::node_ptr node_ptr
key_compare key_comp() const
Returns the compare function used for the key.
void copy_structure(const Self &other)
Copy the exact sturcture of the sub-tree pointed to by other_node into the current empty tree...
node_ptr create_node(const value_type &value)
std::pair< NodePtr, dimension_type > minimum_mapping(NodePtr node, dimension_type dim, Rank rank, dimension_type map, KeyCompare key_comp)
Move the iterator given in parameter to the minimum value along the iterator's mapping dimension but ...
node_ptr node
The node pointed to by the iterator.
bool empty() const
True if the tree is empty.
node_ptr erase_node(dimension_type node_dim, node_ptr node)
Erase the node located at node with current dimension node_dim.
const_reverse_iterator crend() const
iterator insert(const value_type &value)
Insert a single value element in the container.
size_type max_size() const
The maximum number of elements that can be allocated.
bool operator==(const Kdtree< Rank, Key, Value, Compare, Alloc > &lhs, const Kdtree< Rank, Key, Value, Compare, Alloc > &rhs)
The == and != operations is performed by first comparing sizes, and if they match, the elements are compared sequentially using algorithm std::equal, which stops at the first mismatch.
dimension_type dimension() const
Returns the dimension of the tree.
const_iterator find(const key_type &key) const
Find the first node that matches with key and returns an iterator to it found, otherwise it returns a...
std::reverse_iterator< const_iterator > const_reverse_iterator
void swap(Self &other)
Swap the K-d tree content with others.
The basic node for any tree in the library.
const_node_ptr get_rightmost() const
mode_type::const_node_ptr const_node_ptr
bool operator()(const Node_ptr &x, const Node_ptr &y) const
const_iterator end() const
ordered_iterator< Container > ordered_begin(Container &container)
Finds the value in container for which its key has the smallest coordinate over the dimension ordered...
const_iterator begin() const
Kdtree(const rank_type &rank_, const key_compare &compare_, const allocator_type &allocator_)
bool operator>=(const Kdtree< Rank, Key, Value, Compare, Alloc > &lhs, const Kdtree< Rank, Key, Value, Compare, Alloc > &rhs)
Operations <, >, <= and >= behave as if using algorithm lexicographical_compare, which compares the e...
Node< Link > * maximum(Node< Link > *x)
Reach the left most node.
Implementation(const rank_type &rank, const key_compare &compare, const Link_allocator &alloc)
Node * left
A pointer to the left child node of the current node.
const Kdtree_link< Key, Value >::value_type & const_value(const Node< Kdtree_link< Key, Value > > *node)
This function converts a pointer on a node into a value for a Kdtree_link type.
const Kdtree_link< Value, Value >::key_type & const_key(const Node< Kdtree_link< Value, Value > > *node)
This function converts a pointer on a node into a key for a Kdtree_link type.
void erase(iterator pointer)
Deletes the node pointed to by the iterator.
std::vector< node_ptr >::iterator median(typename std::vector< node_ptr >::iterator first, typename std::vector< node_ptr >::iterator last, dimension_type dim)
This function finds the median node in a random iterator range.
bool header(const Node< Link > *x)
Check if node is a header node.
mode_type::const_link_ptr const_link_ptr
Tp * mutate_pointer(const Tp *p)
A helper functions that mutates pointers.
std::reverse_iterator< iterator > reverse_iterator
Node< Link > * minimum(Node< Link > *x)
Reach the left most node.
bool operator!=(const Kdtree< Rank, Key, Value, Compare, Alloc > &lhs, const Kdtree< Rank, Key, Value, Compare, Alloc > &rhs)
The == and != operations is performed by first comparing sizes, and if they match, the elements are compared sequentially using algorithm std::equal, which stops at the first mismatch.
iterator find(const key_type &key)
Find the first node that matches with key and returns an iterator to it found, otherwise it returns a...
Value compare functor for container storing pairs of (Key, Mapped) types, such as in spatial::point_m...
size_type size() const
Returns the number of elements in the K-d tree.
rank_type rank() const
Returns the rank used to create the tree.
node_ptr node
The node pointed to by the iterator.
bool operator>(const Kdtree< Rank, Key, Value, Compare, Alloc > &lhs, const Kdtree< Rank, Key, Value, Compare, Alloc > &rhs)
Operations <, >, <= and >= behave as if using algorithm lexicographical_compare, which compares the e...
value_compare value_comp() const
Returns the compare function used for the value.
void check_iterator(Ptr1 ptr1, Ptr2 ptr2)
Checks if two iterators are of equal values, if not raises the invalid_iterator exception.
const_reverse_iterator rbegin() const
ordered_iterator< Container > ordered_end(Container &container)
Finds the past-the-end position in container for this constant iterator.
const_node_ptr get_root() const
const_node_ptr get_header() const
std::size_t dimension_type
Defines the type for the dimension as being a size.
Definition: spatial.hpp:71
Maximum(const key_compare &key_comp, node_ptr node_)
allocator_type get_allocator() const
Returns the allocator used by the tree.
void destroy_all_nodes()
Destroy and deallocate all nodes in the container.
mapping_compare(const Compare &c, dimension_type d)
ValueCompare< value_type, key_compare > value_compare
Link_allocator & get_link_allocator()
std::ptrdiff_t difference_type
void assign(Type1 &first, Type2 &second, const std::pair< Type1, Type2 > &pair)
spatial::details::Kdtree::Implementation _impl
const_node_ptr get_leftmost() const
reverse_iterator rbegin()
void insert(InputIterator first, InputIterator last)
Insert a serie of values in the container at once.
The main namespace used in the library.
Definition: algorithm.hpp:23
void set_leftmost(node_ptr x)
void set_rightmost(node_ptr x)
void clear()
Erase all elements in the K-d tree.
const Base & base() const
Accessor to the base class.
node_ptr rebalance_node_insert(typename std::vector< node_ptr >::iterator first, typename std::vector< node_ptr >::iterator last, dimension_type dim, node_ptr header)
Insert all the nodes in [first,last) into the tree, by first sorting the nodes according to the dimen...
const_iterator cend() const
void swap_node(Node< Kdtree_link< Key, Value > > *&a, Node< Kdtree_link< Key, Value > > *&b)
Swaps nodes position in the tree.
Detailed implementation of the kd-tree.
size_type count() const
Returns the number of elements in the K-d tree.
Node * right
A pointer to the right child node of the current node.
Self & operator=(const Self &other)
Assignment of other into the tree, with deep copy.
Kdtree_link< Key, Value > * link(Node< Kdtree_link< Key, Value > > *node)
This function converts a pointer on a node into a link for a Kdtree_link type.
Value_allocator get_value_allocator() const
void copy_rebalance(const Self &other)
Copy the content of other to the tree and rebalances the values in the tree resulting in most query h...
mode_type::link_ptr link_ptr
Kdtree_link< Key, Value >::value_type & value(Node< Kdtree_link< Key, Value > > *node)
This function converts a pointer on a node into a value for a Kdtree_link type.
std::pair< NodePtr, dimension_type > preorder_first(NodePtr node, dimension_type dim, Rank rank, const Query &query)
Kdtree_link< Key, Value > mode_type
Kdtree(const Self &other, bool balancing=false)
Deep copy of other into the new tree.
void check_node_iterator(Node *node)
Checks that the node pointed to by an iterator and given as an argument to a function is not null or ...
Alloc::template rebind< value_type >::other Value_allocator
Node * parent
A pointer to the parent of the current node.
Compress< key_compare, size_type > _count
void swap(Kdtree< Rank, Key, Value, Compare, Alloc > &left, Kdtree< Rank, Key, Value, Compare, Alloc > &right)
Swap the content of the tree left and right.
Kdtree(const rank_type &rank_)
const_reverse_iterator crbegin() const
Node_iterator< mode_type > iterator
void destroy_node(node_ptr node)
Destroy and deallocate node.
Kdtree(const rank_type &rank_, const key_compare &compare_)
void insert_rebalance(InputIterator first, InputIterator last)
Insert a serie of values in the container at once and rebalance the container after insertion...
std::ptrdiff_t random_access_iterator_distance(InputIterator first, InputIterator last, std::random_access_iterator_tag)
Kdtree< Rank, Key, Value, Compare, Alloc > Self
reverse_iterator rend()
dimension_type incr_dim(Rank rank, dimension_type node_dim)
Increment dimension node_dim, given rank.