diff --git a/map/CMakeLists.txt b/map/CMakeLists.txt index 83e4d26..c99cc2f 100644 --- a/map/CMakeLists.txt +++ b/map/CMakeLists.txt @@ -13,21 +13,21 @@ add_executable(mp_five_mem ${CMAKE_CURRENT_SOURCE_DIR}/data/five.memcheck/code.c add_test(NAME mp_one COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_one >/tmp/one_out.txt\ && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/one/answer.txt /tmp/one_out.txt>/tmp/one_diff.txt") add_test(NAME mp_one_mem COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_one_mem >/tmp/one_mem_out.txt\ - && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/one/answer.txt /tmp/one_mem_out.txt>/tmp/one_mem_diff.txt") + && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/one.memcheck/answer.txt /tmp/one_mem_out.txt>/tmp/one_mem_diff.txt") add_test(NAME mp_two COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_two >/tmp/two_out.txt\ && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/two/answer.txt /tmp/two_out.txt>/tmp/two_diff.txt") add_test(NAME mp_two_mem COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_two_mem >/tmp/two_mem_out.txt\ - && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/two/answer.txt /tmp/two_mem_out.txt>/tmp/two_mem_diff.txt") + && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/two.memcheck/answer.txt /tmp/two_mem_out.txt>/tmp/two_mem_diff.txt") add_test(NAME mp_three COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_three >/tmp/three_out.txt\ && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/three/answer.txt /tmp/three_out.txt>/tmp/three_diff.txt") add_test(NAME mp_three_mem COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_three_mem >/tmp/three_mem_out.txt\ - && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/three/answer.txt /tmp/three_mem_out.txt>/tmp/three_mem_diff.txt") + && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/three.memcheck/answer.txt /tmp/three_mem_out.txt>/tmp/three_mem_diff.txt") add_test(NAME mp_four COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_four >/tmp/four_out.txt\ && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/four/answer.txt /tmp/four_out.txt>/tmp/four_diff.txt") add_test(NAME mp_four_mem COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_four_mem >/tmp/four_mem_out.txt\ - && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/four/answer.txt /tmp/four_mem_out.txt>/tmp/four_mem_diff.txt") + && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/four.memcheck/answer.txt /tmp/four_mem_out.txt>/tmp/four_mem_diff.txt") add_test(NAME mp_five COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_five >/tmp/five_out.txt\ && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/five/answer.txt /tmp/five_out.txt>/tmp/five_diff.txt") add_test(NAME mp_five_mem COMMAND sh -c "${CMAKE_CURRENT_BINARY_DIR}/mp_five_mem >/tmp/five_mem_out.txt\ - && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/five/answer.txt /tmp/five_mem_out.txt>/tmp/five_mem_diff.txt") + && diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/five.memcheck/answer.txt /tmp/five_mem_out.txt>/tmp/five_mem_diff.txt") add_subdirectory(test) \ No newline at end of file diff --git a/map/src/map.hpp b/map/src/map.hpp index a6794b6..9d8b727 100644 --- a/map/src/map.hpp +++ b/map/src/map.hpp @@ -243,7 +243,7 @@ class map { successor->color = color_of_node; if (parent_of_successor == node) { successor->left = left_of_node; - successor->right = right_of_node; + successor->right = node; successor->SetChildrensParent(); successor->parent = parent_of_node; path_of_node = successor; @@ -264,8 +264,8 @@ class map { } } void DeleteFixUp(RedBlackTreeNodeType *&tree_root) { - assert(this->left == nullptr && this->right == nullptr); assert(this->color == RedBlackTreeColorType::BLACK); + if (this == tree_root) return; RedBlackTreeNodeType *sibling = GetSibling(); assert(sibling != nullptr); if (sibling->color == RedBlackTreeColorType::RED) { @@ -294,8 +294,6 @@ class map { (distant_nephew == nullptr || distant_nephew != nullptr && distant_nephew->color == RedBlackTreeColorType::BLACK)) { // Case 2 - assert(close_nephew == nullptr); - assert(distant_nephew == nullptr); sibling->color = RedBlackTreeColorType::RED; this->parent->color = RedBlackTreeColorType::BLACK; return; @@ -305,8 +303,6 @@ class map { (distant_nephew == nullptr || distant_nephew != nullptr && distant_nephew->color == RedBlackTreeColorType::BLACK)) { // Case 3 - assert(close_nephew == nullptr); - assert(distant_nephew == nullptr); sibling->color = RedBlackTreeColorType::RED; this->parent->DeleteFixUp(tree_root); return; @@ -328,13 +324,11 @@ class map { assert(distant_nephew != nullptr && distant_nephew->color == RedBlackTreeColorType::RED); // Then it must be Case 5 if (this == parent->left) { - sibling->color = parent->color; - parent->color = RedBlackTreeColorType::BLACK; + std::swap(sibling->color, parent->color); distant_nephew->color = RedBlackTreeColorType::BLACK; parent->RotateLeft(tree_root); } else { - sibling->color = parent->color; - parent->color = RedBlackTreeColorType::BLACK; + std::swap(sibling->color, parent->color); distant_nephew->color = RedBlackTreeColorType::BLACK; parent->RotateRight(tree_root); } @@ -351,7 +345,7 @@ class map { RedBlackTreeNodeType *successor = pos->right; while (successor->left != nullptr) successor = successor->left; SwapNodeWithItsSuccessor(pos, successor, tree_root); - DeleteNode(successor, tree_root); + DeleteNode(pos, tree_root); return; } if (pos->left == nullptr && pos->right == nullptr) { diff --git a/map/test/test_basic.cpp b/map/test/test_basic.cpp index 3f7f461..e72ec51 100644 --- a/map/test/test_basic.cpp +++ b/map/test/test_basic.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "map.hpp" TEST(BasicTests, GTestItSelf) { @@ -61,4 +62,66 @@ TEST(BasicTests, MassiveOperatorInsert) { EXPECT_EQ(mp_it->first, st_it->first); EXPECT_EQ(mp_it->second, st_it->second); } +} + +TEST(BasicTests, BasicOperationErase) { + sjtu::map mp; + mp[1] = 2; + mp[3] = 4; + mp[5] = 7; + mp[9] = 11; + auto it = mp.find(3); + mp.erase(it); + EXPECT_EQ(mp.size(), 3); + it = mp.begin(); + EXPECT_EQ(it->first, 1); + EXPECT_EQ(it->second, 2); + it++; + EXPECT_EQ(it->first, 5); + EXPECT_EQ(it->second, 7); + it++; + EXPECT_EQ(it->first, 9); + EXPECT_EQ(it->second, 11); +} + +TEST(BasicTests, MassiveOperationErase) { + std::mt19937 rnd(2333333); + sjtu::map map; + std::map standard_map; + int nodes = 7, range = 7; + for (int i = 0; i < nodes; ++i) { + int key = rnd() % range; + int value = rnd() % range; + map[key] = value; + standard_map[key] = value; + std::cerr << "inserting " << key << " " << value << "\n"; + } + std::vector keys; + for (auto items : standard_map) keys.push_back(items.first); + for (int i = 0; i < nodes / 2; ++i) { + int kid = rnd() % keys.size(); + int key = keys[kid]; + std::cerr << "erasing " << key << "\n"; + map.erase(map.find(key)); + standard_map.erase(key); + keys.erase(keys.begin() + kid); +#ifndef NDEBUG + EXPECT_TRUE(map.RedBlackTreeStructureCheck()); +#endif + } + auto mp_it = map.begin(); + auto st_it = standard_map.begin(); + EXPECT_EQ(map.size(), standard_map.size()); + for (; mp_it != map.end(); mp_it++, st_it++) { + EXPECT_EQ(mp_it->first, st_it->first); + EXPECT_EQ(mp_it->second, st_it->second); + } + mp_it = map.end(); + st_it = standard_map.end(); + for (int i = 0; i < map.size(); ++i) { + mp_it--; + st_it--; + EXPECT_EQ(mp_it->first, st_it->first); + EXPECT_EQ(mp_it->second, st_it->second); + } } \ No newline at end of file