write basic structure and insert

This commit is contained in:
2024-03-25 16:02:07 +00:00
parent 543ebb28cb
commit c585b59f7a
2 changed files with 456 additions and 175 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
/build /build
/.cache /.cache
.clang-format .clang-format
/map/src/std.hpp

View File

@ -5,186 +5,466 @@
#define SJTU_MAP_HPP #define SJTU_MAP_HPP
// only for std::less<T> // only for std::less<T>
#include <functional> #include <cassert>
#include <cstddef> #include <cstddef>
#include "utility.hpp" #include <functional>
#include "exceptions.hpp" #include "exceptions.hpp"
#include "utility.hpp"
namespace sjtu { namespace sjtu {
template< template <class Key, class T, class Compare = std::less<Key> >
class Key, class map {
class T, public:
class Compare = std::less<Key> /**
> class map { * the internal type of data.
public: * it should have a default constructor, a copy constructor.
/** * You can use sjtu::map as value_type by typedef.
* the internal type of data. */
* it should have a default constructor, a copy constructor. typedef pair<const Key, T> value_type;
* You can use sjtu::map as value_type by typedef.
*/
typedef pair<const Key, T> value_type;
/**
* see BidirectionalIterator at CppReference for help.
*
* if there is anything wrong throw invalid_iterator.
* like it = map.begin(); --it;
* or it = map.end(); ++end();
*/
class const_iterator;
class iterator {
private:
/**
* TODO add data members
* just add whatever you want.
*/
public:
iterator() {
// TODO
}
iterator(const iterator &other) {
// TODO
}
/**
* TODO iter++
*/
iterator operator++(int) {}
/**
* TODO ++iter
*/
iterator & operator++() {}
/**
* TODO iter--
*/
iterator operator--(int) {}
/**
* TODO --iter
*/
iterator & operator--() {}
/**
* a operator to check whether two iterators are same (pointing to the same memory).
*/
value_type & operator*() const {}
bool operator==(const iterator &rhs) const {}
bool operator==(const const_iterator &rhs) const {}
/**
* some other operator for iterator.
*/
bool operator!=(const iterator &rhs) const {}
bool operator!=(const const_iterator &rhs) const {}
/** private:
* for the support of it->first. static Compare comparer;
* See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. /**
*/ * The NIL Node is recorded as a nullptr pointer.
value_type* operator->() const noexcept {} */
}; struct RedBlackTreeNodeType {
class const_iterator { value_type val;
// it should has similar member method as iterator. RedBlackTreeNodeType *left, *right, *parent;
// and it should be able to construct from an iterator. enum RedBlackTreeColorType { RED, BLACK } color;
private: RedBlackTreeNodeType() : left(nullptr), right(nullptr), parent(nullptr), color(RED) {}
// data members. RedBlackTreeNodeType(const value_type &val, RedBlackTreeNodeType *left, RedBlackTreeNodeType *right,
public: RedBlackTreeNodeType *parent, RedBlackTreeColorType color)
const_iterator() { : val(val), left(left), right(right), parent(parent), color(color) {}
// TODO inline RedBlackTreeNodeType *GetGrandParent() const noexcept {
} if (parent == nullptr)
const_iterator(const const_iterator &other) { #if __cplusplus >= 202002L
// TODO [[unlikely]]
} #endif
const_iterator(const iterator &other) { return nullptr;
// TODO return parent->parent;
} }
// And other methods in iterator. inline RedBlackTreeNodeType *GetUncle() const noexcept {
// And other methods in iterator. RedBlackTreeNodeType *grand_parent = GetGrandParent();
// And other methods in iterator. if (grand_parent == nullptr)
}; #if __cplusplus >= 202002L
/** [[unlikely]]
* TODO two constructors #endif
*/ return nullptr;
map() {} if (parent == grand_parent->left)
map(const map &other) {} return grand_parent->right;
/** else
* TODO assignment operator return grand_parent->left;
*/ }
map & operator=(const map &other) {} inline RedBlackTreeNodeType *GetSibling() const noexcept {
/** if (parent == nullptr)
* TODO Destructors #if __cplusplus >= 202002L
*/ [[unlikely]]
~map() {} #endif
/** return nullptr;
* TODO if (this == parent->left)
* access specified element with bounds checking return parent->right;
* Returns a reference to the mapped value of the element with key equivalent to key. else
* If no such element exists, an exception of type `index_out_of_bound' return parent->left;
*/ }
T & at(const Key &key) {} inline RedBlackTreeNodeType *&GetSelfPath(RedBlackTreeNodeType *&tree_root) noexcept {
const T & at(const Key &key) const {} if (parent == nullptr) return tree_root;
/** if (this == parent->left)
* TODO return parent->left;
* access specified element else
* Returns a reference to the value that is mapped to a key equivalent to key, return parent->right;
* performing an insertion if such key does not already exist. }
*/ inline void SetChildrensParent() noexcept {
T & operator[](const Key &key) {} if (left != nullptr) left->parent = this;
/** if (right != nullptr) right->parent = this;
* behave like at() throw index_out_of_bound if such key does not exist. }
*/ inline void RotateLeft(RedBlackTreeNodeType *&tree_root) noexcept {
const T & operator[](const Key &key) const {} assert(this->right != nullptr);
/** RedBlackTreeNodeType *parent_backup = parent;
* return a iterator to the beginning RedBlackTreeNodeType *&path = this->GetSelfPath(tree_root);
*/ RedBlackTreeNodeType *replacement = this->right;
iterator begin() {} this->right = replacement->left;
const_iterator cbegin() const {} replacement->left = this;
/** this->SetChildrensParent();
* return a iterator to the end replacement->SetChildrensParent();
* in fact, it returns past-the-end. path = replacement;
*/ replacement->parent = parent_backup;
iterator end() {} }
const_iterator cend() const {} inline void RotateRight(RedBlackTreeNodeType *&tree_root) noexcept {
/** assert(this->left != nullptr);
* checks whether the container is empty RedBlackTreeNodeType *parent_backup = parent;
* return true if empty, otherwise false. RedBlackTreeNodeType *&path = this->GetSelfPath(tree_root);
*/ RedBlackTreeNodeType *replacement = this->left;
bool empty() const {} this->left = replacement->right;
/** replacement->right = this;
* returns the number of elements. this->SetChildrensParent();
*/ replacement->SetChildrensParent();
size_t size() const {} path = replacement;
/** replacement->parent = parent_backup;
* clears the contents }
*/ void InsertFixUp(RedBlackTreeNodeType *&tree_root) {
void clear() {} if (parent == nullptr) {
/** // Case 1
* insert an element. color = RedBlackTreeColorType::BLACK;
* return a pair, the first of the pair is return;
* the iterator to the new element (or the element that prevented the insertion), }
* the second one is true if insert successfully, or false. if (parent->color == RedBlackTreeColorType::BLACK) return;
*/ if (parent->parent == nullptr) {
pair<iterator, bool> insert(const value_type &value) {} // Case 2 & 3
/** parent->color = RedBlackTreeColorType::BLACK;
* erase the element at pos. return;
* }
* throw if pos pointed to a bad element (pos == this->end() || pos points an element out of this) RedBlackTreeNodeType *uncle = GetUncle();
*/ RedBlackTreeColorType *grand_parent = GetGrandParent();
void erase(iterator pos) {} if (uncle != nullptr && uncle->color == RedBlackTreeColorType::RED) {
/** // Case 4
* Returns the number of elements with key parent->color = RedBlackTreeColorType::BLACK;
* that compares equivalent to the specified argument, uncle->color = RedBlackTreeColorType::BLACK;
* which is either 1 or 0 grand_parent->color = RedBlackTreeColorType::RED;
* since this container does not allow duplicates. grand_parent->InsertFixUp(tree_root);
* The default method of check the equivalence is !(a < b || b > a) return;
*/ }
size_t count(const Key &key) const {} if (grand_parent->left == parent) {
/** if (parent->right == this) {
* Finds an element with key equivalent to key. parent->RotateLeft(tree_root);
* key value of the element to search for. assert(parent->parent == this);
* Iterator to an element with key equivalent to key. parent->InsertFixUp(tree_root);
* If no such element is found, past-the-end (see end()) iterator is returned. return;
*/ }
iterator find(const Key &key) {} grand_parent->RotateRight(tree_root);
const_iterator find(const Key &key) const {} assert(grand_parent->parent == parent);
parent->color = RedBlackTreeColorType::BLACK;
grand_parent->color = RedBlackTreeColorType::RED;
} else {
if (parent->left == this) {
parent->RotateRight(tree_root);
assert(parent->parent == this);
parent->InsertFixUp(tree_root);
return;
}
grand_parent->RotateLeft(tree_root);
assert(grand_parent->parent == parent);
parent->color = RedBlackTreeColorType::BLACK;
grand_parent->color = RedBlackTreeColorType::RED;
}
}
/**
* @brief Insert a new node into the tree.
*
* @details This function will insert a new node into the tree. If insert successfully, it will return true.
*
* @param tree_root The root of the tree.
* @param val The value to be inserted.
* @param allow_replacement Whether to allow replacement if the key already exists.
*
* @return Whether the insertion is successful.
*
* @note Note that tree_root is a reference to the root of the tree. This function will modify the tree_root if
* necessary.
*/
bool Insert(RedBlackTreeNodeType *&tree_root, const value_type &val, bool allow_replacement) {
if (comparer(val.first, this->val.first)) {
if (left == nullptr) {
left = new RedBlackTreeNodeType(val, nullptr, nullptr, this, RedBlackTreeColorType::RED);
left->parent = this;
left->InsertFixUp(tree_root);
} else {
return left->Insert(tree_root, val, allow_replacement);
}
} else if (comparer(this->val.first, val.first)) {
if (right == nullptr) {
right = new RedBlackTreeNodeType(val, nullptr, nullptr, this, RedBlackTreeColorType::RED);
right->parent = this;
right->InsertFixUp(tree_root);
} else {
return right->Insert(tree_root, val, allow_replacement);
}
} else {
if (allow_replacement) {
this->val = val;
return true;
}
}
return false;
}
/**
* @brief The definition of ReleaseAll.
*
* @details This fuction will be called when the whole map is destructed. It will release all the memory allocated.
*
* @note Note that the node itself must be released outside this function.
*/
void ReleaseAll() {
if (left) left->ReleaseAll();
if (right) right->ReleaseAll();
delete left;
delete right;
}
};
size_t node_count;
RedBlackTreeNodeType *tree_root;
public:
/**
* see BidirectionalIterator at CppReference for help.
*
* if there is anything wrong throw invalid_iterator.
* like it = map.begin(); --it;
* or it = map.end(); ++end();
*/
class const_iterator;
class iterator;
friend iterator;
friend const_iterator;
class iterator {
private:
RedBlackTreeNodeType *raw_pointer; // when iterator points to end(), raw_pointer=nullptr
map *domain;
public:
iterator() : raw_pointer(nullptr), domain(nullptr) {}
iterator(const iterator &other) : raw_pointer(other.raw_pointer), domain(other.domain) {}
iterator(RedBlackTreeNodeType *raw_pointer, map *domain) : raw_pointer(raw_pointer), domain(domain) {}
iterator &operator++() {
if (raw_pointer == nullptr) throw invalid_iterator();
if (raw_pointer->right != nullptr) {
raw_pointer = raw_pointer->right;
while (raw_pointer->left != nullptr) raw_pointer = raw_pointer->left;
} else {
RedBlackTreeNodeType *backup = raw_pointer;
while (raw_pointer->parent != nullptr && raw_pointer->parent->right == raw_pointer)
raw_pointer = raw_pointer->parent;
if (raw_pointer->parent == nullptr) {
raw_pointer = nullptr;
return *this;
}
raw_pointer = raw_pointer->parent;
}
return *this;
}
iterator operator++(int) {
iterator tmp = *this;
++*this;
return tmp;
}
iterator &operator--() {
if (raw_pointer == nullptr) {
if (domain == nullptr) throw invalid_iterator();
raw_pointer = domain->tree_root;
while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right;
return *this;
}
if (raw_pointer->left != nullptr) {
raw_pointer = raw_pointer->left;
while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right;
} else {
RedBlackTreeNodeType *backup = raw_pointer;
while (raw_pointer->parent != nullptr && raw_pointer->parent->left == raw_pointer)
raw_pointer = raw_pointer->parent;
if (raw_pointer->parent == nullptr) {
throw invalid_iterator();
raw_pointer = nullptr;
return *this;
}
raw_pointer = raw_pointer->parent;
}
return *this;
}
iterator operator--(int) {
iterator tmp = *this;
--*this;
return tmp;
}
/**
* a operator to check whether two iterators are same (pointing to the same memory).
*/
value_type &operator*() const {
if (raw_pointer == nullptr) throw invalid_iterator();
return raw_pointer->val;
}
bool operator==(const iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
bool operator==(const const_iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
/**
* some other operator for iterator.
*/
bool operator!=(const iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
bool operator!=(const const_iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
/**
* for the support of it->first.
* See
* <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/>
* for help.
*/
value_type *operator->() const noexcept { return &raw_pointer->val; }
};
class const_iterator {
private:
RedBlackTreeNodeType *raw_pointer; // when iterator points to end(), raw_pointer=nullptr
const map *domain;
public:
const_iterator() : raw_pointer(nullptr), domain(nullptr) {}
const_iterator(const const_iterator &other) : raw_pointer(other.raw_pointer), domain(other.domain) {}
const_iterator(const iterator &other) : raw_pointer(other.raw_pointer), domain(other.domain) {}
const_iterator(RedBlackTreeNodeType *raw_pointer, const map *domain) : raw_pointer(raw_pointer), domain(domain) {}
const_iterator &operator++() {
if (raw_pointer == nullptr) throw invalid_iterator();
if (raw_pointer->right != nullptr) {
raw_pointer = raw_pointer->right;
while (raw_pointer->left != nullptr) raw_pointer = raw_pointer->left;
} else {
RedBlackTreeNodeType *backup = raw_pointer;
while (raw_pointer->parent != nullptr && raw_pointer->parent->right == raw_pointer)
raw_pointer = raw_pointer->parent;
if (raw_pointer->parent == nullptr) {
raw_pointer = nullptr;
return *this;
}
raw_pointer = raw_pointer->parent;
}
return *this;
}
const_iterator operator++(int) {
const_iterator tmp = *this;
++*this;
return tmp;
}
const_iterator &operator--() {
if (raw_pointer == nullptr) {
if (domain == nullptr) throw invalid_iterator();
raw_pointer = domain->tree_root;
while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right;
return *this;
}
if (raw_pointer->left != nullptr) {
raw_pointer = raw_pointer->left;
while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right;
} else {
RedBlackTreeNodeType *backup = raw_pointer;
while (raw_pointer->parent != nullptr && raw_pointer->parent->left == raw_pointer)
raw_pointer = raw_pointer->parent;
if (raw_pointer->parent == nullptr) {
throw invalid_iterator();
raw_pointer = nullptr;
return *this;
}
raw_pointer = raw_pointer->parent;
}
return *this;
}
const_iterator operator--(int) {
const_iterator tmp = *this;
--*this;
return tmp;
}
/**
* a operator to check whether two iterators are same (pointing to the same memory).
*/
const value_type &operator*() const {
if (raw_pointer == nullptr) throw invalid_iterator();
return raw_pointer->val;
}
bool operator==(const iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
bool operator==(const const_iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
/**
* some other operator for iterator.
*/
bool operator!=(const iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
bool operator!=(const const_iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
value_type *operator->() const noexcept { return &raw_pointer->val; }
};
map() : node_count(0), tree_root(nullptr) {}
// TODO copy constructor
map(const map &other) {}
/**
* TODO assignment operator
*/
map &operator=(const map &other) {}
~map() {
if (tree_root) tree_root->ReleaseAll();
delete tree_root;
}
/**
* TODO
* access specified element with bounds checking
* Returns a reference to the mapped value of the element with key equivalent to key.
* If no such element exists, an exception of type `index_out_of_bound'
*/
T &at(const Key &key) {}
const T &at(const Key &key) const {}
/**
* TODO
* access specified element
* Returns a reference to the value that is mapped to a key equivalent to key,
* performing an insertion if such key does not already exist.
*/
T &operator[](const Key &key) {}
/**
* behave like at() throw index_out_of_bound if such key does not exist.
*/
const T &operator[](const Key &key) const {}
/**
* return a iterator to the beginning
*/
iterator begin() {}
const_iterator cbegin() const {}
/**
* return a iterator to the end
* in fact, it returns past-the-end.
*/
iterator end() {}
const_iterator cend() const {}
/**
* checks whether the container is empty
* return true if empty, otherwise false.
*/
bool empty() const { return node_count == 0; }
/**
* returns the number of elements.
*/
size_t size() const { return node_count; }
/**
* clears the contents
*/
void clear() {}
/**
* insert an element.
* return a pair, the first of the pair is
* the iterator to the new element (or the element that prevented the insertion),
* the second one is true if insert successfully, or false.
*/
pair<iterator, bool> insert(const value_type &value) {
if (tree_root == nullptr) {
tree_root = new RedBlackTreeNodeType(value, nullptr, nullptr, nullptr, RedBlackTreeNodeType::BLACK);
node_count = 1;
return pair<iterator, bool>(iterator(tree_root), true);
}
}
/**
* erase the element at pos.
*
* throw if pos pointed to a bad element (pos == this->end() || pos points an element out of this)
*/
void erase(iterator pos) {}
/**
* Returns the number of elements with key
* that compares equivalent to the specified argument,
* which is either 1 or 0
* since this container does not allow duplicates.
* The default method of check the equivalence is !(a < b || b > a)
*/
size_t count(const Key &key) const {}
/**
* Finds an element with key equivalent to key.
* key value of the element to search for.
* Iterator to an element with key equivalent to key.
* If no such element is found, past-the-end (see end()) iterator is returned.
*/
iterator find(const Key &key) {}
const_iterator find(const Key &key) const {}
}; };
} } // namespace sjtu
#endif #endif