From e61832f7cd1d7fa2a2301056fcc9d79931d86254 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Thu, 13 Aug 2020 22:58:35 +0100 Subject: [PATCH] Add erase test for scapegoat tree. Fix build as needed, implement find(). --- include/duckhandy/implem/scapegoat_tree.inl | 32 +++++++++-- include/duckhandy/implem/tree_iterator.inl | 4 +- include/duckhandy/scapegoat_tree.hpp | 4 +- test/unit/scapegoat_tree_test.cpp | 63 +++++++++++++++++++++ 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/include/duckhandy/implem/scapegoat_tree.inl b/include/duckhandy/implem/scapegoat_tree.inl index 690f650..b4fb8d9 100644 --- a/include/duckhandy/implem/scapegoat_tree.inl +++ b/include/duckhandy/implem/scapegoat_tree.inl @@ -559,7 +559,7 @@ namespace duckmem { ///------------------------------------------------------------------------- ///------------------------------------------------------------------------- template - typename ScapegoatTree::NodeType* ScapegoatTree::find_ifp (const NodeType* parTree, const K& parKey) { + typename ScapegoatTree::NodeType* ScapegoatTree::find_ifp (NodeType* parTree, const K& parKey) { while (parTree) { if (parKey < parTree->content) parTree = parTree->left; @@ -632,7 +632,7 @@ namespace duckmem { ///------------------------------------------------------------------------- template bool ScapegoatTree::include (const K& parSearch) const { - const NodeType* const found = FindIFP(m_root, parSearch); + const NodeType* const found = find_ifp(m_root, parSearch); Assert(not found or not (parSearch < found->content or found->content < parSearch)); return static_cast(NULL != found); } @@ -654,7 +654,7 @@ namespace duckmem { ///------------------------------------------------------------------------- template void ScapegoatTree::erase (iterator parItem) { - NodeType* const dele = parItem->GetPointer(); + NodeType* const dele = parItem.GetPointer(); AssertRelease(NULL != dele); Assert(m_count > 0); @@ -662,7 +662,7 @@ namespace duckmem { if (dele == m_root) parent = m_root; else - parent = FindParentIFP(m_root, dele); + parent = find_parent_ifp(m_root, dele); Assert(NULL != parent); if (parent) { @@ -675,7 +675,7 @@ namespace duckmem { parentChildRef = (dele->left ? dele->left : dele->right); } else { - NodeType* const inorderSuccessor = DetachBottomNode(dele, true); + NodeType* const inorderSuccessor = detach_bottom_node(dele, true); parentChildRef = inorderSuccessor; inorderSuccessor->left = dele->left; @@ -689,6 +689,28 @@ namespace duckmem { rebalance_after_deletion_ifn(); } + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + inline typename ScapegoatTree::iterator ScapegoatTree::find (const K& parSearch) { + NodeStack stack; + const size_type depthHint = get_max_balanced_depth(std::max(m_reserved, m_count + 1), m_alphainvloginv) + 3; + stack.reserve(depthHint); + NodeType* const closestMatch = get_insert_parent(m_root, parSearch, stack); + Assert(stack.size() <= depthHint); + if (closestMatch->content == parSearch) + return iterator(stack.begin(), stack.size(), depthHint); + else + return this->end(); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + inline typename ScapegoatTree::const_iterator ScapegoatTree::find (const K& parSearch) const { + return const_cast*>(this)->find(parSearch); + } + // ///------------------------------------------------------------------------- // ///------------------------------------------------------------------------- // template diff --git a/include/duckhandy/implem/tree_iterator.inl b/include/duckhandy/implem/tree_iterator.inl index 8425641..e3ad5dc 100644 --- a/include/duckhandy/implem/tree_iterator.inl +++ b/include/duckhandy/implem/tree_iterator.inl @@ -44,9 +44,9 @@ namespace duckmem { std::vector

localCopy; localCopy.reserve(parOther.m_stack.size()); while (not otherStackCopy.empty()) { - P convertedItem = otherStackCopy.top(); + P convertedItem = otherStackCopy.back(); localCopy.push_back(convertedItem); - otherStackCopy.pop(); + otherStackCopy.pop_back(); } m_stack.reserve(parOther.m_stack.capacity()); for (typename std::vector

::reverse_iterator itRev = localCopy.rbegin(), itRevEnd = localCopy.rend(); itRev != itRevEnd; ++itRev) { diff --git a/include/duckhandy/scapegoat_tree.hpp b/include/duckhandy/scapegoat_tree.hpp index f653d18..6b44caf 100644 --- a/include/duckhandy/scapegoat_tree.hpp +++ b/include/duckhandy/scapegoat_tree.hpp @@ -117,6 +117,8 @@ namespace duckmem { void erase ( iterator parItem ); void erase ( iterator parFrom, iterator parLast ); size_type erase ( const value_type& parKey ); + iterator find ( const K& parSearch ); + const_iterator find ( const K& parSearch ) const; iterator begin ( void ); const_iterator begin ( void ) const; @@ -127,7 +129,7 @@ namespace duckmem { template static T* find_closest_match ( T* parTree, const K& parKey ); static NodeType* get_insert_parent ( NodeType* parTree, const K& parKey, NodeStack& parRewind ); - static NodeType* find_ifp ( const NodeType* parTree, const K& parKey ); + static NodeType* find_ifp ( NodeType* parTree, const K& parKey ); static NodeType* find_parent_ifp ( NodeType* parTree, const NodeType* parSearchNodeAddr ); static NodeType* get_new_node ( const K& parKey ); static void delete_nodes ( NodeType* parNode ); diff --git a/test/unit/scapegoat_tree_test.cpp b/test/unit/scapegoat_tree_test.cpp index cf531b8..3ec1217 100644 --- a/test/unit/scapegoat_tree_test.cpp +++ b/test/unit/scapegoat_tree_test.cpp @@ -17,6 +17,7 @@ #include "catch2/catch.hpp" #include "duckhandy/scapegoat_tree.hpp" +#include TEST_CASE ("Insert values in a ScapegoatTree", "[Scapegoat][ScapegoatTree][containers]") { using duckmem::ScapegoatTree; @@ -87,3 +88,65 @@ TEST_CASE ("Insert values in a ScapegoatTree", "[Scapegoat][ScapegoatTree][conta } } +TEST_CASE ("Erase values from a ScapegoatTree", "[Scapegoat][ScapegoatTree][containers]") { + using duckmem::ScapegoatTree; + + //auto rand_num = std::bind(std::uniform_int_distribution(1, 1000), std::mt19937(std::time(0))); + + ScapegoatTree tree; + for (int z = 0; z < 5000; ++z) { + tree.insert(z + 1); + } + CHECK(tree.size() == 5000); + + std::set cpy(tree.begin(), tree.end()); + CHECK(cpy.size() == 5000); + + { + auto it_num = tree.find(0); + CHECK(it_num == tree.end()); + } + { + auto it_num = tree.find(1); + REQUIRE(it_num != tree.end()); + CHECK(*it_num == 1); + CHECK(it_num == tree.begin()); + tree.erase(it_num); + cpy.erase(1); + CHECK(tree.size() == 4999); + it_num = tree.find(1); + CHECK(it_num == tree.end()); + CHECK(not tree.include(1)); + } + { + auto it_num = tree.find(2345); + REQUIRE(it_num != tree.end()); + CHECK(*it_num == 2345); + tree.erase(it_num); + cpy.erase(2345); + CHECK(tree.size() == 4998); + it_num = tree.find(2345); + CHECK(it_num == tree.end()); + CHECK(not tree.include(2345)); + } + { + auto it_num = tree.find(3000); + REQUIRE(it_num != tree.end()); + int test_num = 3000; + for (; it_num != tree.end(); ++it_num) { + CHECK(*it_num == test_num); + test_num++; + } + CHECK(test_num == 5001); + } + { + const ScapegoatTree& ref = tree; + auto it_num = ref.find(18); + REQUIRE(it_num != ref.end()); + CHECK(*it_num == 18); + CHECK(ref.include(18)); + } + + REQUIRE(tree.size() == cpy.size()); + CHECK(std::equal(tree.begin(), tree.end(), cpy.begin())); +}