ready to finish erase
This commit is contained in:
158
map/src/map.hpp
158
map/src/map.hpp
@ -8,6 +8,8 @@
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <queue> // only for debug use
|
||||
#include <vector> // only for debug use
|
||||
#include "exceptions.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@ -126,9 +128,10 @@ class map {
|
||||
}
|
||||
if (grand_parent->left == parent) {
|
||||
if (parent->right == this) {
|
||||
RedBlackTreeNodeType *old_parent = parent;
|
||||
parent->RotateLeft(tree_root);
|
||||
assert(parent->parent == this);
|
||||
parent->InsertFixUp(tree_root);
|
||||
assert(old_parent->parent == this);
|
||||
old_parent->InsertFixUp(tree_root);
|
||||
return;
|
||||
}
|
||||
grand_parent->RotateRight(tree_root);
|
||||
@ -137,9 +140,10 @@ class map {
|
||||
grand_parent->color = RedBlackTreeColorType::RED;
|
||||
} else {
|
||||
if (parent->left == this) {
|
||||
RedBlackTreeNodeType *old_parent = parent;
|
||||
parent->RotateRight(tree_root);
|
||||
assert(parent->parent == this);
|
||||
parent->InsertFixUp(tree_root);
|
||||
assert(old_parent->parent == this);
|
||||
old_parent->InsertFixUp(tree_root);
|
||||
return;
|
||||
}
|
||||
grand_parent->RotateLeft(tree_root);
|
||||
@ -168,8 +172,9 @@ class map {
|
||||
if (left == nullptr) {
|
||||
left = new RedBlackTreeNodeType(val, nullptr, nullptr, this, RedBlackTreeColorType::RED);
|
||||
left->parent = this;
|
||||
RedBlackTreeNodeType *addr = left;
|
||||
left->InsertFixUp(tree_root);
|
||||
return std::pair<RedBlackTreeNodeType *, bool>(left, true);
|
||||
return std::pair<RedBlackTreeNodeType *, bool>(addr, true);
|
||||
} else {
|
||||
return left->Insert(tree_root, val, allow_replacement);
|
||||
}
|
||||
@ -177,8 +182,9 @@ class map {
|
||||
if (right == nullptr) {
|
||||
right = new RedBlackTreeNodeType(val, nullptr, nullptr, this, RedBlackTreeColorType::RED);
|
||||
right->parent = this;
|
||||
RedBlackTreeNodeType *addr = right;
|
||||
right->InsertFixUp(tree_root);
|
||||
return std::pair<RedBlackTreeNodeType *, bool>(right, true);
|
||||
return std::pair<RedBlackTreeNodeType *, bool>(addr, true);
|
||||
} else {
|
||||
return right->Insert(tree_root, val, allow_replacement);
|
||||
}
|
||||
@ -214,6 +220,81 @@ class map {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Swap the node with its successor.
|
||||
*
|
||||
* @details This function will swap the node with its successor.
|
||||
*
|
||||
* @note The color is not swapped.
|
||||
*/
|
||||
inline static void SwapNodeWithItsSuccessor(RedBlackTreeNodeType *node, RedBlackTreeNodeType *successor,
|
||||
RedBlackTreeNodeType *&tree_root) {
|
||||
RedBlackTreeNodeType *left_of_node = node->left;
|
||||
RedBlackTreeNodeType *right_of_node = node->right;
|
||||
RedBlackTreeNodeType *parent_of_node = node->parent;
|
||||
RedBlackTreeColorType color_of_node = node->color;
|
||||
RedBlackTreeNodeType *&path_of_node = node->GetSelfPath(tree_root);
|
||||
RedBlackTreeNodeType *left_of_successor = successor->left;
|
||||
RedBlackTreeNodeType *right_of_successor = successor->right;
|
||||
RedBlackTreeNodeType *parent_of_successor = successor->parent;
|
||||
RedBlackTreeColorType color_of_successor = successor->color;
|
||||
RedBlackTreeNodeType *&path_of_successor = successor->GetSelfPath(tree_root);
|
||||
node->color = color_of_successor;
|
||||
successor->color = color_of_node;
|
||||
if (parent_of_successor == node) {
|
||||
successor->left = left_of_node;
|
||||
successor->right = right_of_node;
|
||||
successor->SetChildrensParent();
|
||||
successor->parent = parent_of_node;
|
||||
path_of_node = successor;
|
||||
node->left = left_of_successor;
|
||||
node->right = right_of_successor;
|
||||
node->SetChildrensParent();
|
||||
} else {
|
||||
successor->left = left_of_node;
|
||||
successor->right = right_of_node;
|
||||
successor->SetChildrensParent();
|
||||
successor->parent = parent_of_node;
|
||||
path_of_node = successor;
|
||||
node->left = left_of_successor;
|
||||
node->right = right_of_successor;
|
||||
node->SetChildrensParent();
|
||||
node->parent = parent_of_successor;
|
||||
path_of_successor = node;
|
||||
}
|
||||
}
|
||||
static void DeleteNode(RedBlackTreeNodeType *pos, RedBlackTreeNodeType *&tree_root) {
|
||||
if (pos->parent == nullptr && pos->left == nullptr && pos->right == nullptr) {
|
||||
// Case 0: The only node in the tree.
|
||||
delete pos;
|
||||
tree_root = nullptr;
|
||||
return;
|
||||
}
|
||||
if (pos->left != nullptr && pos->right != nullptr) {
|
||||
// Case 1: The node has two children. Then we swap the node with its successor and just delete the successor.
|
||||
RedBlackTreeNodeType *successor = pos->right;
|
||||
while (successor->left != nullptr) successor = successor->left;
|
||||
SwapNodeWithItsSuccessor(pos, successor, tree_root);
|
||||
DeleteNode(successor, tree_root);
|
||||
return;
|
||||
}
|
||||
if (pos->left == nullptr && pos->right == nullptr) {
|
||||
// Case 2
|
||||
if (pos->color == RedBlackTreeColorType::RED) {
|
||||
pos->GetSelfPath(tree_root) = nullptr;
|
||||
delete pos;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Case 3
|
||||
RedBlackTreeNodeType *replacement = (pos->left != nullptr ? pos->left : pos->right);
|
||||
assert(replacement != nullptr);
|
||||
assert(replacement->color == RedBlackTreeColorType::RED);
|
||||
pos->GetSelfPath(tree_root) = replacement;
|
||||
replacement->parent = pos->parent;
|
||||
replacement->color = RedBlackTreeColorType::BLACK;
|
||||
delete pos;
|
||||
}
|
||||
};
|
||||
size_t node_count;
|
||||
RedBlackTreeNodeType *tree_root;
|
||||
@ -470,6 +551,12 @@ class map {
|
||||
* performing an insertion if such key does not already exist.
|
||||
*/
|
||||
T &operator[](const Key &key) {
|
||||
if (node_count == 0) {
|
||||
tree_root =
|
||||
new RedBlackTreeNodeType(value_type(key, T()), nullptr, nullptr, nullptr, RedBlackTreeNodeType::BLACK);
|
||||
++node_count;
|
||||
return tree_root->val.second;
|
||||
}
|
||||
auto result = tree_root->Insert(tree_root, value_type(key, T()), false);
|
||||
if (result.second) ++node_count;
|
||||
return result.first->val.second;
|
||||
@ -540,6 +627,8 @@ class map {
|
||||
*/
|
||||
void erase(iterator pos) {
|
||||
if (pos.domain != this || pos.raw_pointer == nullptr) throw invalid_iterator();
|
||||
RedBlackTreeNodeType::DeleteNode(pos.raw_pointer, tree_root);
|
||||
--node_count;
|
||||
}
|
||||
/**
|
||||
* Returns the number of elements with key
|
||||
@ -566,6 +655,63 @@ class map {
|
||||
if (tree_root == nullptr) return cend();
|
||||
return const_iterator(tree_root->Find(key), this);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
bool RedBlackTreeStructureCheck() {
|
||||
if (tree_root == nullptr) return node_count == 0;
|
||||
if (node_count == 0) return false;
|
||||
std::queue<RedBlackTreeNodeType *> Q;
|
||||
std::vector<RedBlackTreeNodeType *> NIL_leafs;
|
||||
size_t actual_node_count = 0;
|
||||
Q.push(tree_root);
|
||||
while (!Q.empty()) {
|
||||
RedBlackTreeNodeType *current = Q.front();
|
||||
Q.pop();
|
||||
if (current->color == RedBlackTreeNodeType::RED) {
|
||||
if (current->left != nullptr && current->left->color == RedBlackTreeNodeType::RED) return false;
|
||||
if (current->right != nullptr && current->right->color == RedBlackTreeNodeType::RED) return false;
|
||||
}
|
||||
if (current->left != nullptr)
|
||||
Q.push(current->left);
|
||||
else
|
||||
NIL_leafs.push_back(current);
|
||||
if (current->right != nullptr)
|
||||
Q.push(current->right);
|
||||
else
|
||||
NIL_leafs.push_back(current);
|
||||
++actual_node_count;
|
||||
}
|
||||
if (actual_node_count != node_count) return false;
|
||||
if (tree_root->color != RedBlackTreeNodeType::BLACK) return false;
|
||||
if (tree_root->parent != nullptr) return false;
|
||||
assert(NIL_leafs.size() >= 2);
|
||||
size_t correct_black_nodes = 1;
|
||||
RedBlackTreeNodeType *ptr = NIL_leafs[0];
|
||||
while (ptr) {
|
||||
if (ptr->color == RedBlackTreeNodeType::BLACK) ++correct_black_nodes;
|
||||
ptr = ptr->parent;
|
||||
}
|
||||
for (auto ptr : NIL_leafs) {
|
||||
size_t black_nodes = 1;
|
||||
while (ptr) {
|
||||
if (ptr->color == RedBlackTreeNodeType::BLACK) ++black_nodes;
|
||||
ptr = ptr->parent;
|
||||
}
|
||||
if (black_nodes != correct_black_nodes) return false;
|
||||
}
|
||||
// Now check whether it is a binary search tree. Use a lambda expression to get inorder tree walk.
|
||||
std::vector<Key> key_array;
|
||||
std::function<void(RedBlackTreeNodeType *)> inorder_walk = [&](RedBlackTreeNodeType *node) {
|
||||
if (node->left != nullptr) inorder_walk(node->left);
|
||||
key_array.push_back(node->val.first);
|
||||
if (node->right != nullptr) inorder_walk(node->right);
|
||||
};
|
||||
inorder_walk(tree_root);
|
||||
for (size_t i = 1; i < key_array.size(); ++i) {
|
||||
if (!comparer(key_array[i - 1], key_array[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
// Define the static member comparer.
|
||||
template <class Key, class T, class Compare>
|
||||
|
Reference in New Issue
Block a user