Bladeren bron

Fixing clear() to run in O(n) time and O(1) space.

Samuel Jaffe 8 jaren geleden
bovenliggende
commit
1da7efc8ef
2 gewijzigde bestanden met toevoegingen van 31 en 6 verwijderingen
  1. 3 2
      trie.hpp
  2. 28 4
      trie_impl.hpp

+ 3 - 2
trie.hpp

@@ -25,7 +25,7 @@ class trie {
 private:
   using self_t = trie<K, V, Compare>;
   using layer_t = value_ptr<self_t>;
-  using backing_t = std::map<K, const_propogating_ptr<not_null<layer_t>>, Compare>;
+  using backing_t = std::map<K, const_propogating_ptr<layer_t>, Compare>;
   template <typename KS>
   using is_collection_t = typename std::enable_if<std::is_same<K, std::decay_t<decltype(*std::begin(std::declval<KS>()))>>::value>::type;
 
@@ -50,6 +50,7 @@ public:
   trie(mapped_type const & value);
   trie(trie const & other);
   trie(trie && other) = default;
+  ~trie();
   self_t & operator=(mapped_type const & value);
   self_t & operator=(trie const & value);
   self_t & operator=(trie && value) = default;
@@ -92,7 +93,7 @@ public:
   local_const_reverse_iterator local_rbegin() const { return impl_.rbegin(); }
   local_const_reverse_iterator local_rend() const { return impl_.rend(); }
   
-  void clear() { impl_.clear(); value_ = mapped_type{}; }
+  void clear();
 private:
   friend bool operator==(trie const & lhs, trie const & rhs) {
     auto it1 = lhs.begin(), it2 = rhs.begin(), end1 = lhs.end(), end2 = lhs.end();

+ 28 - 4
trie_impl.hpp

@@ -27,6 +27,11 @@ trie<K, V, C>::trie(trie const & other) {
   }
 }
 
+template <typename K, typename V, typename C>
+trie<K, V, C>::~trie() {
+  clear();
+}
+
 template <typename K, typename V, typename C>
 auto trie<K, V, C>::operator=(mapped_type const & value) -> self_t & {
   value_ = value;
@@ -35,12 +40,14 @@ auto trie<K, V, C>::operator=(mapped_type const & value) -> self_t & {
 
 template <typename K, typename V, typename C>
 auto trie<K, V, C>::operator=(trie const & other) -> self_t & {
-  for (const_iterator it = other.begin(), end = other.end(); it != end; ++it) {
-    insert(it.keys, *it);
-  }
+  trie tmp{other};
+  swap(*this, tmp);
   return *this;
 }
 
+// n := total elements
+// d := average depth
+// Operations: O(d*log(n/d))
 template <typename K, typename V, typename C>
 template <typename KS, typename>
 auto trie<K, V, C>::operator[](KS const & keys) -> self_t & {
@@ -51,6 +58,9 @@ auto trie<K, V, C>::operator[](KS const & keys) -> self_t & {
   return *rec;
 }
 
+// n := total elements
+// d := average depth
+// Operations: O(log(n))
 template <typename K, typename V, typename C>
 auto trie<K, V, C>::operator[](key_type const & key) -> self_t & {
   auto it = impl_.lower_bound(key);
@@ -60,6 +70,9 @@ auto trie<K, V, C>::operator[](key_type const & key) -> self_t & {
   return *(it->second);
 }
 
+// n := total elements
+// d := average depth
+// Operations: O(d*log(n/d))
 template <typename K, typename V, typename C>
 auto trie<K, V, C>::operator[](std::initializer_list<key_type> keys) -> self_t & {
   self_t * rec = this;
@@ -85,6 +98,17 @@ auto trie<K, V, C>::insert(key_type const & key, mapped_type const & value) -> s
   auto it = impl_.lower_bound(key);
   if ( it == impl_.end() || key_compare()(key, it->first) ) {
     return { impl_.emplace_hint(it, key, make_value<self_t>(value)), true };
+
+// n := total elements
+// d := average depth
+// Stack: O(1)
+// Operations: O(n)
+template <typename K, typename V, typename C>
+void trie<K, V, C>::clear() {
+  for (reverse_iterator it = rbegin(), end = rend(); it != end && !it.iters.empty(); ++it) {
+    auto ptr = std::move(it.iters.top()->second);
+    ptr->impl_.clear();
   }
-  return { it, false };
+  value_ = mapped_type{};
+  impl_.clear();
 }