suffering from memory corruption issues, not sure where the issue is
This commit is contained in:
parent
62cdce3f2e
commit
c48eff8fc7
2 changed files with 172 additions and 58 deletions
180
Map.hpp
180
Map.hpp
|
@ -1,6 +1,8 @@
|
|||
#ifndef _POWELL_CS440
|
||||
#define _POWELL_CS440
|
||||
#include <algorithm>
|
||||
// uncomment on submission/performance test
|
||||
// #define NDEBUG
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
@ -20,9 +22,6 @@ Direction operator!(Direction dir) {
|
|||
assert(false);
|
||||
}
|
||||
}
|
||||
int x5 = 5;
|
||||
int x6 = 6;
|
||||
int x7 = 7;
|
||||
enum class Color { Red, Black };
|
||||
} // namespace
|
||||
template <typename Key_T, typename Mapped_T> class Map {
|
||||
|
@ -31,6 +30,7 @@ template <typename Key_T, typename Mapped_T> class Map {
|
|||
using internal_ValueType = std::pair<Key_T, Mapped_T>;
|
||||
|
||||
struct Node {
|
||||
int valid = 0x13371337;
|
||||
Node *parent;
|
||||
internal_ValueType val;
|
||||
std::unique_ptr<Node> left;
|
||||
|
@ -58,6 +58,10 @@ template <typename Key_T, typename Mapped_T> class Map {
|
|||
: parent{nullptr}, val{std::move(rhs.val)}, left{std::move(rhs.left)},
|
||||
right{std::move(rhs.right)}, color{rhs.color}, prev{nullptr},
|
||||
next{nullptr}, map{rhs.map} {
|
||||
if (rhs.valid != 0x13371337) {
|
||||
std::cerr << "(" << rhs.val.first << ")" << std::endl;
|
||||
}
|
||||
rhs.valid = 0;
|
||||
if (this->left) {
|
||||
this->left->parent = this;
|
||||
}
|
||||
|
@ -171,8 +175,13 @@ template <typename Key_T, typename Mapped_T> class Map {
|
|||
|
||||
// intuitively should be correct but might need to do restore ordering on
|
||||
// both instead
|
||||
dropping->prev->next = dropping->next;
|
||||
dropping->next->prev = dropping->prev;
|
||||
if (dropping->prev != nullptr) {
|
||||
dropping->prev->next = dropping->next;
|
||||
}
|
||||
|
||||
if (dropping->next != nullptr) {
|
||||
dropping->next->prev = dropping->prev;
|
||||
}
|
||||
}
|
||||
void restore_ordering() {
|
||||
this->prev = this->calc_pred();
|
||||
|
@ -246,7 +255,6 @@ template <typename Key_T, typename Mapped_T> class Map {
|
|||
// make ourselves our former child's child
|
||||
this->parent->child(!dir)->set_child(dir, std::move(self));
|
||||
}
|
||||
// TODO:
|
||||
// Referencing
|
||||
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Notes_to_the_insert_diagrams
|
||||
void restore_red_black_insert(Direction dir) {
|
||||
|
@ -310,8 +318,6 @@ template <typename Key_T, typename Mapped_T> class Map {
|
|||
self = grandparent;
|
||||
}
|
||||
}
|
||||
// TODO:
|
||||
void restore_red_black_erase() {}
|
||||
};
|
||||
|
||||
// data needed for implementation
|
||||
|
@ -332,6 +338,15 @@ public:
|
|||
public:
|
||||
friend Map;
|
||||
Iterator() = delete;
|
||||
void check() {
|
||||
assert(underlying->val.first < 200);
|
||||
if (underlying->prev != nullptr) {
|
||||
assert(underlying->prev->val.first < 200);
|
||||
}
|
||||
if (underlying->next != nullptr) {
|
||||
assert(underlying->next->val.first < 200);
|
||||
}
|
||||
}
|
||||
};
|
||||
Map() : root{}, _size{0} {}
|
||||
Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} {}
|
||||
|
@ -362,7 +377,7 @@ private:
|
|||
|
||||
root.value() = std::move(*new_root);
|
||||
|
||||
old_root->set_child(!dir, std::move(root.value().uchild(dir)));
|
||||
old_root->set_child(!dir, root.value().uchild(dir));
|
||||
root.value().set_child(dir, std::move(old_root));
|
||||
}
|
||||
template <bool trace = false>
|
||||
|
@ -420,6 +435,131 @@ private:
|
|||
}
|
||||
return std::make_pair(ret_parent, ret_dir);
|
||||
}
|
||||
void hard_erase(Node *n) {
|
||||
assert(n->parent);
|
||||
Node *parent = n->parent;
|
||||
Direction dir = parent->which_child(n);
|
||||
parent->erase_child(n);
|
||||
goto skip;
|
||||
while (true) {
|
||||
parent = n->parent;
|
||||
if (parent == nullptr) {
|
||||
// we're at root we're done (case 1)
|
||||
return;
|
||||
}
|
||||
dir = parent->which_child(n);
|
||||
skip:
|
||||
Color par_color = parent->color;
|
||||
|
||||
Node *sibling = parent->child(!dir);
|
||||
Color sibling_color = sibling ? sibling->color : Color::Black;
|
||||
|
||||
Node *close = sibling ? sibling->child(dir) : nullptr;
|
||||
Node *distant = sibling ? sibling->child(!dir) : nullptr;
|
||||
|
||||
Color close_color = close ? close->color : Color::Black;
|
||||
Color distant_color = distant ? distant->color : Color::Black;
|
||||
|
||||
#define redcheck(v) if ((v) == Color::Red)
|
||||
// it kinda sucks but I think that goto is genuinely the best solution
|
||||
// here, making methods for cases 4,5 and 6 is a lot of unneeded
|
||||
// bookkeeping
|
||||
redcheck(sibling_color) {
|
||||
// case 3
|
||||
if (parent->parent != nullptr) {
|
||||
parent->rotate(dir);
|
||||
} else {
|
||||
parent->map->rotate_root(dir);
|
||||
}
|
||||
parent->color = Color::Red;
|
||||
sibling->color = Color::Black;
|
||||
sibling = close;
|
||||
|
||||
distant = sibling->child(!dir);
|
||||
if (distant != nullptr && distant->color == Color::Red) {
|
||||
goto case_6;
|
||||
}
|
||||
close = sibling->child(dir);
|
||||
if (close != nullptr && close->color == Color::Red) {
|
||||
goto case_5;
|
||||
}
|
||||
goto case_4;
|
||||
}
|
||||
else redcheck(close_color) {
|
||||
// case 5
|
||||
case_5:
|
||||
assert(sibling);
|
||||
assert(close);
|
||||
sibling->rotate(!dir);
|
||||
sibling->color = Color::Red;
|
||||
close->color = Color::Black;
|
||||
distant = sibling;
|
||||
sibling = close;
|
||||
goto case_6;
|
||||
}
|
||||
else redcheck(distant_color) {
|
||||
// case 6
|
||||
case_6:
|
||||
assert(parent);
|
||||
assert(sibling);
|
||||
assert(distant);
|
||||
if (parent->parent != nullptr) {
|
||||
parent->rotate(dir);
|
||||
} else {
|
||||
parent->map->rotate_root(dir);
|
||||
}
|
||||
Color tmp = parent->color;
|
||||
sibling->color = tmp;
|
||||
parent->color = Color::Black;
|
||||
distant->color = Color::Black;
|
||||
return;
|
||||
}
|
||||
else redcheck(par_color) {
|
||||
// case 4
|
||||
case_4:
|
||||
assert(sibling);
|
||||
sibling->color = Color::Red;
|
||||
parent->color = Color::Black;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// case 2
|
||||
assert(sibling);
|
||||
sibling->color = Color::Red;
|
||||
n = parent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool core_erase(Node *erasing) {
|
||||
// 2 children
|
||||
if (erasing->left && erasing->right) {
|
||||
Node *succ = erasing->next;
|
||||
erasing->val = succ->val;
|
||||
this->core_erase(succ);
|
||||
}
|
||||
// 1 child
|
||||
else if (erasing->left) {
|
||||
*erasing = std::move(*erasing->left);
|
||||
return true;
|
||||
} else if (erasing->right) {
|
||||
*erasing = std::move(*erasing->right);
|
||||
return true;
|
||||
}
|
||||
// no children and root
|
||||
else if (!erasing->parent) {
|
||||
erasing->map->root = std::nullopt;
|
||||
}
|
||||
// no children and red
|
||||
else if (erasing->color == Color::Red) {
|
||||
erasing->parent->erase_child(erasing);
|
||||
}
|
||||
// no children and black
|
||||
else {
|
||||
hard_erase(erasing);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
// baseline find using locate
|
||||
|
@ -483,9 +623,25 @@ public:
|
|||
return std::make_pair(Iterator{new_node}, true);
|
||||
}
|
||||
void erase(Iterator pos) {
|
||||
Node *p = pos.underlying->parent;
|
||||
p->erase_child(pos.underlying);
|
||||
p->restore_red_black_erase();
|
||||
Node *before = pos.underlying->prev;
|
||||
Node *after = pos.underlying->next;
|
||||
|
||||
if (core_erase(pos.underlying)) {
|
||||
pos.underlying->restore_ordering();
|
||||
} else {
|
||||
if (before != nullptr) {
|
||||
before->next = before->calc_succ();
|
||||
if (before->next != nullptr) {
|
||||
before->next->prev = before;
|
||||
}
|
||||
}
|
||||
if (after != nullptr) {
|
||||
after->prev = after->calc_pred();
|
||||
if (after->prev != nullptr) {
|
||||
after->prev->next = after;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// baseline iterator creation
|
||||
|
|
50
t.cpp
50
t.cpp
|
@ -3,9 +3,6 @@
|
|||
template class cs440::Map<int, int>;
|
||||
int main(void) {
|
||||
cs440::Map<int, int> a;
|
||||
int x5 = 5;
|
||||
int x6 = 6;
|
||||
int x7 = 7;
|
||||
a.insert({1, 1});
|
||||
a.insert({2, 2});
|
||||
a.insert({3, 3});
|
||||
|
@ -16,49 +13,10 @@ int main(void) {
|
|||
a.insert({8, 8});
|
||||
a.insert({9, 9});
|
||||
a.insert({10, 10});
|
||||
a.insert({11, 11});
|
||||
a.insert({12, 12});
|
||||
a.insert({13, 13});
|
||||
a.insert({14, 14});
|
||||
a.insert({15, 15});
|
||||
a.insert({16, 16});
|
||||
a.insert({17, 17});
|
||||
a.insert({18, 18});
|
||||
a.insert({19, 19});
|
||||
a.insert({20, 20});
|
||||
a.insert({21, 21});
|
||||
a.insert({22, 22});
|
||||
a.insert({23, 23});
|
||||
a.insert({24, 24});
|
||||
a.insert({25, 25});
|
||||
a.insert({26, 26});
|
||||
a.insert({27, 27});
|
||||
a.insert({28, 28});
|
||||
a.insert({29, 29});
|
||||
a.insert({30, 30});
|
||||
a.insert({31, 31});
|
||||
a.insert({32, 32});
|
||||
a.insert({33, 33});
|
||||
a.insert({34, 34});
|
||||
a.insert({35, 35});
|
||||
a.insert({36, 36});
|
||||
a.insert({37, 37});
|
||||
a.insert({38, 38});
|
||||
a.insert({39, 39});
|
||||
a.insert({40, 40});
|
||||
a.insert({41, 41});
|
||||
a.insert({42, 42});
|
||||
a.insert({43, 43});
|
||||
a.insert({44, 44});
|
||||
a.insert({45, 45});
|
||||
a.insert({46, 46});
|
||||
a.insert({47, 47});
|
||||
a.insert({48, 48});
|
||||
a.insert({49, 49});
|
||||
a.insert({50, 50});
|
||||
for (std::size_t i = 1; i <= 50; i++) {
|
||||
std::cout << i << "\t";
|
||||
a.find_trace(i);
|
||||
for (std::size_t i = 1; i <= 10; i++) {
|
||||
// a.find(i).check();
|
||||
std::cout << i << std::endl;
|
||||
a.erase(a.find(i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue