committing before I redo red-black deletion of black leaf
This commit is contained in:
parent
a0ce38e2ee
commit
f73c68a980
1 changed files with 90 additions and 49 deletions
139
Map.hpp
139
Map.hpp
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue