/**
* implement a container like std::map
*/
#ifndef SJTU_MAP_HPP
#define SJTU_MAP_HPP
#include <cstdio>
// only for std::less<T>
#include <functional>
#include <cstddef>
#include "utility.hpp"
#include "exceptions.hpp"
namespace sjtu {
template<
class Key,
class T,
class Compare = std::less <Key>
> class AAtree{
public:
typedef pair<const Key, T> value_type;
struct Node {
Node *lson, *rson, *parent;
int level;
value_type data;
Node(const value_type &d, int lv = 1, Node *p = nullptr, Node *l = nullptr, Node *r = nullptr)
: data(d), level(lv), parent(p), lson(l), rson(r) {}
~Node() {
data.~value_type();
}
};
Node *root;
size_t tree_size;
Compare comp;
AAtree(): root(nullptr), tree_size(0) {}
AAtree(const AAtree &other) {
root = copyTree(other.root, nullptr);
tree_size = other.tree_size;
}
AAtree &operator=(const AAtree &other) {
if (this != &other) {
clear(root);
root = copyTree(other.root, nullptr);
tree_size = other.tree_size;
}
return *this;
}
~AAtree() {
clear(root);
tree_size = 0;
}
Node *skew(Node *node) {
if (!node || !node->lson) return node;
if (node->lson->level == node->level) {
Node *L = node->lson;
node->lson = L->rson;
if (L->rson) L->rson->parent = node;
L->rson = node;
L->parent = node->parent;
node->parent = L;
return L;
}
return node;
}
Node *split(Node *node) {
if (!node || !node->rson || !node->rson->rson) return node;
if (node->level == node->rson->rson->level) {
Node *R = node->rson;
node->rson = R->lson;
if (R->lson) R->lson->parent = node;
R->lson = node;
R->parent = node->parent;
node->parent = R;
++R->level;
return R;
}
return node;
}
Node *insert(Node *node, const value_type &value, Node *parent = nullptr) {
if (!node) {
++tree_size;
return new Node(value, 1, parent);
}
if (comp(value.first, node->data.first)) {
node->lson = insert(node->lson, value, node);
node->lson->parent = node;
} else if (comp(node->data.first, value.first)) {
node->rson = insert(node->rson, value, node);
node->rson->parent = node;
} else return node;
node = skew(node);
node = split(node);
return node;
}
// 删除节点时正确处理父子关系
// void erase(Node*& node, const Key& key) {
// if (!node) return;
// if (comp(key, node->data.first)) {
// erase(node->lson, key);
// } else if (comp(node->data.first, key)) {
// erase(node->rson, key);
// } else {
// if (node->lson && node->rson) {
// // 处理有两个子节点的情况
// Node* successor = findMin(node->rson);
// Node *newNode = new Node(successor->data, node->level, node->parent, node->lson, node->rson);
// if (newNode->lson) newNode->lson->parent = newNode;
// if (newNode->rson) newNode->rson->parent = newNode;
// if (newNode->parent) {
// if (newNode->parent->lson == node) {
// newNode->parent->lson = newNode;
// } else {
// newNode->parent->rson = newNode;
// }
// }
// erase(newNode->rson, successor->data.first); // 递归删除后继节点
// delete node;
// node = newNode;
// } else {
// Node* temp = node;
// node = (node->lson) ? node->lson : node->rson;
// delete temp; // 释放内存后,node指针已被上层更新
// }
// }
// // 删除后重新平衡
// if (node) {
// node = skew(node);
// node = split(node);
// }
// }
Node *erase(Node *node, const Key &key) {
if (!node) return nullptr;
if (comp(key, node->data.first)) {
node->lson = erase(node->lson, key);
if (node->lson) node->lson->parent = node;
} else if (comp(node->data.first, key)) {
node->rson = erase(node->rson, key);
if (node->rson) node->rson->parent = node;
} else {
if (!node->lson && !node->rson) {
if (node->parent) {
if (node->parent->lson == node) {
node->parent->lson = nullptr;
} else {
node->parent->rson = nullptr;
}
}
delete node;
node = nullptr;
--tree_size;
return nullptr;
} else if (!node->lson) {
Node *temp = node->rson;
temp->parent = node->parent;
delete node;
node = nullptr;
--tree_size;
return temp;
} else if (!node->rson) {
Node *temp = node->lson;
temp->parent = node->parent;
delete node;
node = nullptr;
--tree_size;
return temp;
}
Node *predecessor = node->lson;
while (predecessor->rson) predecessor = predecessor->rson;
Node *newNode = new Node(predecessor->data, node->level, node->parent, node->lson, node->rson);
if (newNode->lson) newNode->lson->parent = newNode;
if (newNode->rson) newNode->rson->parent = newNode;
if (newNode->parent) {
if (newNode->parent->lson == node) {
newNode->parent->lson = newNode;
} else {
newNode->parent->rson = newNode;
}
}
newNode->lson = erase(newNode->lson, predecessor->data.first);
if (newNode->lson) newNode->lson->parent = newNode;
delete node;
node = newNode;
}
if (node->lson && node->rson) {
size_t min_level = node->lson->level < node->rson->level ? node->lson->level : node->rson->level;
if (node->level > min_level + 1) {
node->level = min_level + 1;
if (node->rson && node->rson->level > node->level)
node->rson->level = node->level;
}
}
node = skew(node);
node->rson = skew(node->rson);
if (node->rson) node->rson->rson = skew(node->rson->rson);
node = split(node);
node->rson = split(node->rson);
return node;
}
Node *find(Node *node, const Key &key) const {
while (node) {
if (comp(key, node->data.first)) node = node->lson;
else if (comp(node->data.first, key)) node = node->rson;
else return node;
}
return nullptr;
}
Node *findMin(Node *node) const {
if (!node) return nullptr;
// printf("In findmin: %d\n", (node));
while (node->lson) node = node->lson;
// printf("finish find min\n");
return node;
}
Node *findMax(Node *node) const {
if (!node) return nullptr;
while (node->rson) node = node->rson;
return node;
}
Node *successor(Node *node) const {
// printf("in successor\n");
if (!node) return nullptr;
// printf("in successor2\n");
if (node->rson) return findMin(node->rson);
// printf("in successor3\n");
Node *parent = node->parent;
while (parent && node == parent->rson) {
node = parent;
parent = parent->parent;
}
// printf("finish successor\n");
return parent;
}
Node *predecessor(Node *node) const {
if (!node) return nullptr;
if (node->lson) return findMax(node->lson);
Node *parent = node->parent;
while (parent && node == parent->lson) {
node = parent;
parent = parent->parent;
}
return parent;
}
Node *copyTree(Node *node, Node *parent) {
if (!node) return nullptr;
Node *newNode = new Node(node->data, node->level, parent);
newNode->lson = copyTree(node->lson, newNode);
newNode->rson = copyTree(node->rson, newNode);
return newNode;
}
void clear(Node *node) {
if (!node) return;
clear(node->lson);
clear(node->rson);
delete node;
node = nullptr;
}
};
template<
class Key,
class T,
class Compare = std::less <Key>
> class map {
public:
/**
* the internal type of data.
* it should have a default constructor, a copy constructor.
* You can use sjtu::map as value_type by typedef.
*/
typedef pair<const Key, T> value_type;
AAtree<Key, T, Compare> aa_tree;
/**
* see BidirectionalIterator at CppReference for help.
*
* if there is anything wrong throw invalid_iterator.
* like it = map.begin(); --it;
* or it = map.end(); ++end();
*/
typedef typename AAtree<Key, T, Compare>::Node Node;
class const_iterator;
class iterator {
private:
/**
* TODO add data members
* just add whatever you want.
*/
map* container;
Node *node;
public:
iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) {
// TODO
}
iterator(const iterator &other):container(other.container), node(other.node) {
// TODO
}
/**
* TODO iter++
*/
iterator operator++(int) {
if (!node) throw invalid_iterator();
iterator temp = *this;
node = container->aa_tree.successor(node);
return temp;
}
/**
* TODO ++iter
*/
iterator &operator++() {
if (!node) throw invalid_iterator();
node = container->aa_tree.successor(node);
return *this;
}
/**
* TODO iter--
*/
iterator operator--(int) {
iterator temp = *this;
if (node == nullptr) {
node = container->aa_tree.findMax(container->aa_tree.root);
if (!node) throw invalid_iterator();
} else {
node = container->aa_tree.predecessor(node);
if (!node) throw invalid_iterator();
}
return temp;
}
/**
* TODO --iter
*/
iterator &operator--() {
if (node == nullptr) {
node = container->aa_tree.findMax(container->aa_tree.root);
if (!node) throw invalid_iterator();
} else {
node = container->aa_tree.predecessor(node);
if (!node) throw invalid_iterator();
}
return *this;
}
/**
* a operator to check whether two iterators are same (pointing to the same memory).
*/
value_type &operator*() const {
if (!node) throw invalid_iterator();
return node->data;
}
bool operator==(const iterator &rhs) const {
return node == rhs.node && container == rhs.container;
}
bool operator==(const const_iterator &rhs) const {
return node == rhs.getNode() && container == rhs.getContainer();
}
/**
* some other operator for iterator.
*/
bool operator!=(const iterator &rhs) const {
return node != rhs.node || container != rhs.container;
}
bool operator!=(const const_iterator &rhs) const {
return node != rhs.getNode() || container != rhs.getContainer();
}
map *getContainer() const {
return container;
}
Node *getNode() const {
return node;
}
/**
* 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 {
// if (!node) throw invalid_iterator();
return &(node->data);
}
};
class const_iterator {
// it should has similar member method as iterator.
// and it should be able to construct from an iterator.
private:
// data members.
map* container;
Node *node;
public:
// const_iterator(const map *c = nullptr, Node *n = nullptr): container(const_cast<map*>(c)), node(n) {
// // TODO
// }
const_iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) {
// TODO
}
const_iterator(const const_iterator &other): container(other.container), node(other.node) {
// TODO
}
const_iterator(const iterator &other) {
// TODO
container = other.getContainer();
node = other.getNode();
}
/**
* TODO iter++
*/
const_iterator operator++(int) {
if (!node) throw invalid_iterator();
const_iterator temp = *this;
node = container->aa_tree.successor(node);
return temp;
}
/**
* TODO ++iter
*/
const_iterator &operator++() {
if (!node) throw invalid_iterator();
node = container->aa_tree.successor(node);
return *this;
}
/**
* TODO iter--
*/
const_iterator operator--(int) {
const_iterator temp = *this;
if (node == nullptr) {
node = container->aa_tree.findMax(container->aa_tree.root);
if (!node) throw invalid_iterator();
} else {
node = container->aa_tree.predecessor(node);
if (!node) throw invalid_iterator();
}
return temp;
}
/**
* TODO --iter
*/
const_iterator &operator--() {
if (node == nullptr) {
node = container->aa_tree.findMax(container->aa_tree.root);
if (!node) throw invalid_iterator();
} else {
node = container->aa_tree.predecessor(node);
if (!node) throw invalid_iterator();
}
return *this;
}
/**
* a operator to check whether two iterators are same (pointing to the same memory).
*/
const value_type &operator*() const {
if (!node) throw invalid_iterator();
return node->data;
}
bool operator==(const iterator &rhs) const {
return node == rhs.getNode() && container == rhs.getContainer();
}
bool operator==(const const_iterator &rhs) const {
return node == rhs.node && container == rhs.container;
}
/**
* some other operator for iterator.
*/
bool operator!=(const iterator &rhs) const {
return node != rhs.getNode() || container != rhs.getContainer();
}
bool operator!=(const const_iterator &rhs) const {
return node != rhs.node || container != rhs.container;
}
map *getContainer() const {
return container;
}
Node *getNode() const {
return node;
}
/**
* 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.
*/
const value_type *operator->() const
noexcept {
// if (!node) throw invalid_iterator();
return &(node->data);
}
};
/**
* TODO two constructors
*/
map(): aa_tree() {}
map(const map &other): aa_tree(other.aa_tree) {}
/**
* TODO assignment operator
*/
map &operator=(const map &other) {
if (this != &other) {
aa_tree = other.aa_tree;
}
return *this;
}
/**
* TODO Destructors
*/
~map() {}
/**
* 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) {
auto node = aa_tree.find(aa_tree.root, key);
if (!node) throw index_out_of_bound();
return node->data.second;
}
const T &at(const Key &key) const {
auto node = aa_tree.find(aa_tree.root, key);
if (!node) throw index_out_of_bound();
return node->data.second;
}
/**
* 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) {
auto node = aa_tree.find(aa_tree.root, key);
if (node) return node->data.second;
aa_tree.root = aa_tree.insert(aa_tree.root, value_type(key, T()));
return aa_tree.find(aa_tree.root, key)->data.second;
}
/**
* behave like at() throw index_out_of_bound if such key does not exist.
*/
const T &operator[](const Key &key) const {
return at(key);
}
/**
* return a iterator to the beginning
*/
iterator begin() {
return iterator(this, aa_tree.findMin(aa_tree.root));
}
const_iterator cbegin() const {
return const_iterator(const_cast<map*>(this), aa_tree.findMin(aa_tree.root));
}
/**
* return a iterator to the end
* in fact, it returns past-the-end.
*/
iterator end() {
return iterator(this, nullptr);
}
const_iterator cend() const {
return const_iterator(const_cast<map*>(this), nullptr);
}
/**
* checks whether the container is empty
* return true if empty, otherwise false.
*/
bool empty() const {
return aa_tree.tree_size == 0;
}
/**
* returns the number of elements.
*/
size_t size() const {
return aa_tree.tree_size;
}
/**
* clears the contents
*/
void clear() {
aa_tree.clear(aa_tree.root);
aa_tree.root = nullptr;
aa_tree.tree_size = 0;
}
/**
* 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) {
auto node = aa_tree.find(aa_tree.root, value.first);
if (node) return {iterator(this, node), false};
aa_tree.root = aa_tree.insert(aa_tree.root, value);
node = aa_tree.find(aa_tree.root, value.first);
return {iterator(this, node), 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) {
if (pos == end() || pos.getContainer() != this) throw invalid_iterator();
aa_tree.root = aa_tree.erase(aa_tree.root, (*pos).first);
}
/**
* 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 {
return aa_tree.find(aa_tree.root, key) ? 1 : 0;
}
/**
* 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) {
return iterator(this, aa_tree.find(aa_tree.root, key));
}
const_iterator find(const Key &key) const {
return const_iterator(const_cast<map*>(this), aa_tree.find(aa_tree.root, key));
}
};
}
#endif
这段代码,Q.erase(it--)会失效,为什么?
最新发布