RBTree iterator
This commit is contained in:
parent
732633451e
commit
814d88737e
239
src/RBTree.hpp
239
src/RBTree.hpp
@ -4,9 +4,9 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// template<typename TKey, typename TVal>
|
// typedef char* TKey;
|
||||||
typedef char* TKey;
|
// typedef char* TVal;
|
||||||
typedef char* TVal;
|
template<typename TKey, typename TVal>
|
||||||
class RBTree {
|
class RBTree {
|
||||||
enum class Color {
|
enum class Color {
|
||||||
Red, Black
|
Red, Black
|
||||||
@ -20,11 +20,9 @@ class RBTree {
|
|||||||
Node* left = nullptr;
|
Node* left = nullptr;
|
||||||
Node* right = nullptr;
|
Node* right = nullptr;
|
||||||
|
|
||||||
Node(TKey _key, TVal _val, Color _color, Node* _parent){
|
Node(TKey _key, TVal _val, Color _color, Node* _parent)
|
||||||
key = _key;
|
: key(_key), value(_val), color(_color), parent(_parent)
|
||||||
value = _val;
|
{
|
||||||
color = _color;
|
|
||||||
parent = _parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Node(){
|
~Node(){
|
||||||
@ -53,10 +51,93 @@ class RBTree {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
return parent->getSibling();
|
return parent->getSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// n should be not null
|
||||||
|
Node* getMinChild(){
|
||||||
|
Node* n = this;
|
||||||
|
while(n->left != nullptr)
|
||||||
|
n = n->left;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// n should be not null
|
||||||
|
Node* getMaxChild(){
|
||||||
|
Node* n = this;
|
||||||
|
while(n->right != nullptr)
|
||||||
|
n = n->right;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename TIteratorValue>
|
||||||
|
struct TreeIterator : std::iterator<std::bidirectional_iterator_tag, TIteratorValue> {
|
||||||
|
Node* n;
|
||||||
|
|
||||||
|
TreeIterator(TreeIterator const& src){
|
||||||
|
n = src.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeIterator(Node* ptr){
|
||||||
|
n = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(TreeIterator const& other) const {
|
||||||
|
return n == other.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(TreeIterator const& other) const {
|
||||||
|
return n == other.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator*() const {
|
||||||
|
if(n == nullptr)
|
||||||
|
throw "RBTree::TreeIterator::operator*() error: n == nullptr";
|
||||||
|
return *((pointer)(void*)n);
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeIterator& operator++() {
|
||||||
|
if(n == nullptr)
|
||||||
|
return *this;
|
||||||
|
Node* prev_n = nullptr;
|
||||||
|
while(n->parent != nullptr && (n->right == nullptr || n->right == prev_n)){
|
||||||
|
prev_n = n;
|
||||||
|
n = n->parent;
|
||||||
|
}
|
||||||
|
n = n->right;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeIterator& operator--() {
|
||||||
|
if(n == nullptr)
|
||||||
|
return *this;
|
||||||
|
Node* prev_n = nullptr;
|
||||||
|
while(n->parent != nullptr && (n->left == nullptr || n->left == prev_n)){
|
||||||
|
prev_n = n;
|
||||||
|
n = n->parent;
|
||||||
|
}
|
||||||
|
n = n->left;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Node* root = nullptr;
|
Node* root = nullptr;
|
||||||
|
|
||||||
|
///@returns null if root is null
|
||||||
|
Node* findParentForKey(TKey key) const {
|
||||||
|
Node* n = root;
|
||||||
|
Node* parent = nullptr;
|
||||||
|
while(n != nullptr){
|
||||||
|
parent = n;
|
||||||
|
if(key < n->key)
|
||||||
|
n = n->left;
|
||||||
|
else if(key > n->key)
|
||||||
|
n = n->right;
|
||||||
|
else return nullptr; // key == n->key
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
void rotateLeft(Node* x){
|
void rotateLeft(Node* x){
|
||||||
// 1. get right child of x
|
// 1. get right child of x
|
||||||
Node* y = x->right;
|
Node* y = x->right;
|
||||||
@ -96,19 +177,13 @@ class RBTree {
|
|||||||
x->parent = y;
|
x->parent = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
///@returns null if root is null
|
void transplantNode(Node* old, Node* neww){
|
||||||
Node* findParentForKey(TKey key){
|
neww->parent = old->parent;
|
||||||
Node* n = root;
|
if(old->parent == nullptr)
|
||||||
Node* parent = nullptr;
|
root = neww;
|
||||||
while(n != nullptr){
|
else if(old->parent->left == old)
|
||||||
parent = n;
|
old->parent->left = neww;
|
||||||
if(key < n->key)
|
else old->parent->right = neww;
|
||||||
n = n->left;
|
|
||||||
else if(key > n->key)
|
|
||||||
n = n->right;
|
|
||||||
else return nullptr; // key == n->key
|
|
||||||
}
|
|
||||||
return parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixupInsertion(Node* n){
|
void fixupInsertion(Node* n){
|
||||||
@ -221,30 +296,11 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void transplantNode(Node* old, Node* neww){
|
|
||||||
neww->parent = old->parent;
|
|
||||||
if(old->parent == nullptr)
|
|
||||||
root = neww;
|
|
||||||
else if(old->parent->left == old)
|
|
||||||
old->parent->left = neww;
|
|
||||||
else old->parent->right = neww;
|
|
||||||
}
|
|
||||||
|
|
||||||
// n should be not null
|
|
||||||
Node* getMinimalChild(Node* n){
|
|
||||||
while(n->left != nullptr)
|
|
||||||
n = n->left;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// n should be not null
|
|
||||||
Node* getMaximalChild(Node* n){
|
|
||||||
while(n->right != nullptr)
|
|
||||||
n = n->right;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using iterator = TreeIterator<std::pair<const TKey, TVal>>;
|
||||||
|
using const_iterator = TreeIterator<std::pair<const TKey, const TVal>>;
|
||||||
|
|
||||||
RBTree() {}
|
RBTree() {}
|
||||||
|
|
||||||
~RBTree(){
|
~RBTree(){
|
||||||
@ -252,10 +308,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @param resultPtr nullable
|
||||||
bool tryAdd(TKey key, TVal& value, TVal*& result){
|
bool tryAdd(TKey key, TVal& value, TVal** resultPtr){
|
||||||
if(root == nullptr){
|
if(root == nullptr){
|
||||||
root = new Node(key, value, Color::Black, nullptr);
|
root = new Node(key, value, Color::Black, nullptr);
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = &root->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,20 +325,35 @@ public:
|
|||||||
else nodePtrPtr = &parent->right;
|
else nodePtrPtr = &parent->right;
|
||||||
|
|
||||||
// if a child node already exists at this place, returns false
|
// if a child node already exists at this place, returns false
|
||||||
if(*nodePtrPtr != nullptr)
|
if(*nodePtrPtr != nullptr){
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = nullptr;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// places newNode to left or right of the parent
|
// places newNode to left or right of the parent
|
||||||
Node* newNode = new Node(key, value, Color::Red, parent);
|
Node* newNode = new Node(key, value, Color::Red, parent);
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = &newNode->value;
|
||||||
*nodePtrPtr = newNode;
|
*nodePtrPtr = newNode;
|
||||||
// auto-balancing
|
// auto-balancing
|
||||||
fixupInsertion(newNode);
|
fixupInsertion(newNode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool trySet(TKey key, TVal& value){
|
/// @param resultPtr nullable
|
||||||
if(root == nullptr)
|
bool tryAdd(TKey key, TVal&& value, TVal** resultPtr){
|
||||||
|
return tryAdd(key, value, resultPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @param resultPtr nullable
|
||||||
|
bool trySet(TKey key, TVal& value, TVal** resultPtr){
|
||||||
|
if(root == nullptr){
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = nullptr;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
// ptr to parent->right or parent->left
|
// ptr to parent->right or parent->left
|
||||||
@ -290,17 +363,31 @@ public:
|
|||||||
else nodePtrPtr = &parent->right;
|
else nodePtrPtr = &parent->right;
|
||||||
|
|
||||||
// if a child node with the given key doesn't exist, returns false
|
// if a child node with the given key doesn't exist, returns false
|
||||||
if(*nodePtrPtr == nullptr)
|
if(*nodePtrPtr == nullptr){
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = nullptr;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// replaces the value of left or right child of the parent
|
// replaces the value of left or right child of the parent
|
||||||
(*nodePtrPtr)->value = value;
|
(*nodePtrPtr)->value = value;
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = &(*nodePtrPtr)->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addOrSet(TKey key, TVal& value){
|
/// @param resultPtr nullable
|
||||||
|
bool trySet(TKey key, TVal&& value, TVal** resultPtr){
|
||||||
|
return trySet(key, value, resultPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @param resultPtr nullable
|
||||||
|
void addOrSet(TKey key, TVal& value, TVal** resultPtr){
|
||||||
if(root == nullptr){
|
if(root == nullptr){
|
||||||
root = new Node(key, value, Color::Black, nullptr);
|
root = new Node(key, value, Color::Black, nullptr);
|
||||||
|
if(resultPtr != nullptr)
|
||||||
|
*resultPtr = &root->value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,38 +401,55 @@ public:
|
|||||||
// if a child node already exists at this place, sets it's value
|
// if a child node already exists at this place, sets it's value
|
||||||
if(*nodePtrPtr != nullptr){
|
if(*nodePtrPtr != nullptr){
|
||||||
(*nodePtrPtr)->value = value;
|
(*nodePtrPtr)->value = value;
|
||||||
|
if(resultPtr)
|
||||||
|
*resultPtr = &(*nodePtrPtr)->value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// places newNode to left or right of the parent
|
// places newNode to left or right of the parent
|
||||||
Node* newNode = new Node(key, value, Color::Red, parent);
|
Node* newNode = new Node(key, value, Color::Red, parent);
|
||||||
|
if(resultPtr != nullptr)
|
||||||
|
*resultPtr = &newNode->value;
|
||||||
*nodePtrPtr = newNode;
|
*nodePtrPtr = newNode;
|
||||||
// auto-balancing
|
// auto-balancing
|
||||||
fixupInsertion(newNode);
|
fixupInsertion(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tryGet(TKey key, TVal** result){
|
/// @param resultPtr nullable
|
||||||
|
void addOrSet(TKey key, TVal&& value, TVal** resultPtr){
|
||||||
|
addOrSet(key, value, resultPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool tryGet(TKey key, TVal** resultPtr) const {
|
||||||
|
if(!resultPtr)
|
||||||
|
return false;
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
Node* n;
|
Node* n;
|
||||||
if(key < parent->key)
|
if(key < parent->key)
|
||||||
n = parent->left;
|
n = parent->left;
|
||||||
else n = parent->right;
|
else n = parent->right;
|
||||||
// if there is no node with the given key
|
// if there is no node with the given key
|
||||||
if(n == nullptr)
|
if(n == nullptr){
|
||||||
|
*resultPtr = nullptr;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
*result = &n->value;
|
*resultPtr = &n->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool tryDelete(TKey key){
|
bool tryDelete(TKey key){
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
Node* n;
|
Node* n;
|
||||||
if(key < parent->key)
|
if(key < parent->key)
|
||||||
n = parent->left;
|
n = parent->left;
|
||||||
else n = parent->right;
|
else n = parent->right;
|
||||||
if(n == nullptr) // key not found
|
// key not found
|
||||||
|
if(n == nullptr){
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(n->left == nullptr){
|
if(n->left == nullptr){
|
||||||
transplantNode(n, n->right);
|
transplantNode(n, n->right);
|
||||||
@ -358,7 +462,7 @@ public:
|
|||||||
fixupDeletion(n->left);
|
fixupDeletion(n->left);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Node* minNode = getMinimalChild(n->right);
|
Node* minNode = n->right->getMinChild();
|
||||||
if(minNode != n->right){
|
if(minNode != n->right){
|
||||||
transplantNode(minNode, minNode->right);
|
transplantNode(minNode, minNode->right);
|
||||||
minNode->right = n->right;
|
minNode->right = n->right;
|
||||||
@ -374,4 +478,29 @@ public:
|
|||||||
|
|
||||||
delete n;
|
delete n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
iterator begin(){
|
||||||
|
if(root == nullptr)
|
||||||
|
return iterator(nullptr);
|
||||||
|
return iterator(root->getMinChild());
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end(){
|
||||||
|
if(root == nullptr)
|
||||||
|
return iterator(nullptr);
|
||||||
|
return iterator(root->getMaxChild());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
if(root == nullptr)
|
||||||
|
return const_iterator(nullptr);
|
||||||
|
return const_iterator(root->getMinChild());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
if(root == nullptr)
|
||||||
|
return const_iterator(nullptr);
|
||||||
|
return const_iterator(root->getMaxChild());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user