committing before I redo red-black deletion of black leaf

This commit is contained in:
Pagwin 2024-11-22 21:54:36 -05:00
parent a0ce38e2ee
commit f73c68a980
No known key found for this signature in database
GPG key ID: 81137023740CA260

139
Map.hpp
View file

@ -48,7 +48,6 @@ template <typename Key_T, typename Mapped_T> struct BookKeeping {
BookKeeping(BookKeeping const &rhs)
: container{rhs.container}, value{rhs.value}, // self{rhs.self},
color{rhs.color}, parent{rhs.parent}, left{rhs.left}, right{rhs.right},
// TODO: recalc this
prev{rhs.prev}, next{rhs.next} {}
// if pointing to different containers throws
BookKeeping &operator=(BookKeeping const &rhs) {
@ -62,7 +61,6 @@ template <typename Key_T, typename Mapped_T> struct BookKeeping {
this->parent = rhs.parent;
this->left = rhs.left;
this->right = rhs.right;
// TODO: recalc this
this->prev = rhs.prev;
this->next = rhs.next;
return *this;
@ -353,6 +351,55 @@ private:
std::vector<Node> nodes;
std::size_t size_diff;
std::optional<std::size_t> pred(std::size_t node) {
if (this->nodes[node].left.has_value()) {
std::size_t store = this->nodes[node].left.value();
while (this->nodes[store].right.has_value()) {
store = this->nodes[node].right.value();
}
return store;
} else {
if (!this->nodes[node].parent.has_value()) {
return std::nullopt;
}
std::size_t prev_store = node;
std::size_t store = this->nodes[node].parent.value();
while (this->nodes[store].parent.has_value()) {
if (this->nodes[store].right == prev_store) {
return store;
}
prev_store = store;
store = this->nodes[store].parent.value();
}
return std::nullopt;
}
}
std::optional<std::size_t> succ(std::size_t node) {
if (this->nodes[node].right.has_value()) {
std::size_t store = this->nodes[node].right.value();
while (this->nodes[store].left.has_value()) {
store = this->nodes[node].left.value();
}
return store;
} else {
if (!this->nodes[node].parent.has_value()) {
return std::nullopt;
}
std::size_t prev_store = node;
std::size_t store = this->nodes[prev_store].parent.value();
while (this->nodes[store].parent.has_value()) {
if (this->nodes[store].left == prev_store) {
return store;
}
prev_store = store;
store = this->nodes[store].parent.value();
}
return std::nullopt;
}
}
public:
Map()
: root{std::nullopt}, min{std::nullopt}, max{std::nullopt}, nodes{},
@ -473,18 +520,9 @@ private:
switch (dir) {
case Direction::Left:
// TODO: recalc this
this->nodes[to_insert.value()].next = parent;
this->nodes[to_insert.value()].prev = this->nodes[parent.value()].prev;
this->nodes[parent.value()].prev = to_insert;
this->nodes[parent.value()].left = to_insert;
break;
case Direction::Right:
// TODO: recalc this
this->nodes[to_insert.value()].prev = parent;
this->nodes[to_insert.value()].next = this->nodes[parent.value()].next;
// TODO: recalc this
this->nodes[parent.value()].next = to_insert;
this->nodes[parent.value()].right = to_insert;
break;
}
@ -585,14 +623,21 @@ public:
if (min == std::nullopt ||
val.first < this->nodes[min.value()].value.first) {
min = nodes.size() - 1;
nodes.back().prev = std::nullopt;
}
if (max == std::nullopt ||
val.first > this->nodes[max.value()].value.first) {
max = nodes.size() - 1;
nodes.back().next = std::nullopt;
}
Ref_T successor = this->succ(this->nodes.size() - 1);
Ref_T predessor = this->pred(this->nodes.size() - 1);
if (successor.has_value()) {
this->nodes[successor.value()].prev = this->nodes.size() - 1;
}
this->nodes[this->nodes.size() - 1].next = successor;
if (predessor.has_value()) {
this->nodes[predessor.value()].next = this->nodes.size() - 1;
}
this->nodes[this->nodes.size() - 1].prev = successor;
return std::make_pair(Iterator(*this, nodes.size() - 1), ret);
}
template <typename IT_T> void insert(IT_T range_beg, IT_T range_end) {
@ -688,7 +733,6 @@ private:
}
public:
// TODO: check that the way of reconnecting next and prev works
void erase(Iterator pos) {
this->size_diff++;
// simple cases
@ -703,61 +747,58 @@ public:
}
// 2 children
if (ref->l() != nullptr && ref->r() != nullptr) {
// TODO: recalc this
Ref_T next = ref->next;
Ref_T prev = ref->prev;
*ref = this->nodes[next.value()];
// TODO: recalc this
this->nodes[prev.value()].next = next;
this->nodes[next.value()].prev = prev;
this->erase(Iterator{*this, next});
}
// single child which is left
else if (ref->l() != nullptr && ref->r() == nullptr) {
// TODO: recalc this
Ref_T next = ref->next;
Ref_T prev = ref->prev;
*ref = *ref->l();
this->nodes[prev.value()].next = next;
this->nodes[next.value()].prev = prev;
if (ref->par()->l() == ref) {
ref->par()->set_l(ref->l());
} else {
ref->par()->set_r(ref->l());
}
if (ref->color == Color::Black) {
ref->l()->color = Color::Black;
}
}
// single child which is right
else if (ref->l() == nullptr && ref->r() != nullptr) {
// TODO: recalc this
Ref_T next = ref->next;
Ref_T prev = ref->prev;
*ref = *ref->r();
if (prev.has_value()) {
// TODO: recalc this
this->nodes[prev.value()].next = next;
if (ref->par()->l() == ref) {
ref->par()->set_l(ref->r());
} else {
ref->par()->set_r(ref->r());
}
if (next.has_value()) {
// TODO: recalc this
this->nodes[next.value()].prev = prev;
if (ref->color == Color::Black) {
ref->r()->color = Color::Black;
}
}
// no children and root
else if (ref->l() == nullptr && ref->r() == nullptr) {
else if (this->root == pos.ref && ref->l() == nullptr &&
ref->r() == nullptr) {
this->root = std::nullopt;
}
// no children and red
else if (ref->l() == nullptr && ref->r() == nullptr) {
Node *next =
ref->next.has_value() ? &this->nodes[ref->next.value()] : nullptr;
Node *prev =
ref->prev.has_value() ? &this->nodes[ref->prev.value()] : nullptr;
// TODO: recalc this
prev->next = next != nullptr ? std::optional{next - &this->nodes[0]}
: std::nullopt;
// TODO: recalc this
next->prev = prev != nullptr ? std::optional{prev - &this->nodes[0]}
: std::nullopt;
else if (ref->color == Color::Red && ref->l() == nullptr &&
ref->r() == nullptr) {
if (ref->parent.has_value()) {
if (this->nodes[ref->parent.value()].right == pos.ref.value()) {
this->nodes[ref->parent.value()].right = std::nullopt;
} else {
this->nodes[ref->parent.value()].left = std::nullopt;
}
}
}
// complicated case of black node with no kids
else {
this->complex_erase(pos);
}
if (ref->next.has_value()) {
this->nodes[ref->next.value()].prev = this->pred(ref->next.value());
}
if (ref->prev.has_value()) {
this->nodes[ref->next.value()].next = this->succ(ref->next.value());
}
}
void erase(const Key_T &key) { this->erase(this->find(key)); }
void clear() {