background: COMP 2012H assignment 5
level: *****
最近几周在学template的时候感觉总是心不在焉,导致基本对这些内容没有理解。dekai如今布置了一道用binary search tree的数据结构来实现map的assignment,我也一时间陷入了迷茫。
以前总是觉得写code这件事情的无用功做的太多了,总是想不清楚自己要干什么。
我一位很亲近的朋友告诉我,你写code当然不像你做数学做一道就是一道,你写code自然要花费许多无用功,但是不要不信你所得到的经验。
做每一步都思考的话可能真的会有提高吧。
关于基于template的文件为什么都只有一个hpp文件的原因,是因为这货不像是平常的c++的class或者function了,template这东西只有在被调用的时候才进行实例化,所以如果按平常一样把其定义和声明分开是会造成linker报错的。解决方法是有几个不同的,但是一般都是直接把定义和声明都放在.hpp的文件里面。
(好吧虽然很丑但是我就是这么干了你来打我啊)
#include <iostream>
#include <utility>
#include <iterator>
#ifndef BSTMAP_HPP
#define BSTMAP_HPP
using namespace std;
template<typename Key, typename T>
class bstmap
{
typedef pair<const Key, T> value_type;
typedef bstmap<Key, T> Self;
typedef Key key_type;
typedef T data_type;
typedef T mapped_type;
typedef unsigned int size_type;
typedef int difference_type;
private:
// definition of node struct, use it as a node in the whole tree
// parent_m record parent node
// left_m record left_child, right_m record right_child
struct node_t {
node_t(const pair<const Key,T>& x) : value_m(x),
parent_m(NULL),
left_m(NULL),
right_m(NULL) {}
pair<const Key,T> value_m;
node_t* parent_m;
node_t* left_m;
node_t* right_m;
};
public:
// default constructor of a bstmap
bstmap() : root_m(NULL), size_m(0) {}
// overload copy constructor to do a deep copy
bstmap(const Self& x) {
root_m = _copy(x.root_m);
size_m = x.size_m;
}
public:
class iterator {
public:
typedef std::input_iterator_tag iterator_category;
typedef value_type* pointer;
typedef value_type& reference;
// make bstmap as a friend class so bstmap can use iterator
friend class bstmap;
// we donnot need to deep copy since this iterator point to same container
iterator(bstmap* map, node_t* node) : map_m(map),node_m(node) {}
iterator(const iterator& x) : map_m(x.map_m),node_m(x.node_m) {}
// iterator::it_begin() return the leftmost node in the whole tree
iterator it_begin() {
node_t* result = NULL;
while (node_m != NULL ) {
result = node_m;
node_m = node_m -> left_m;
}
return iterator(map_m,result);
}
// iterator::it_end() return the NULL iterator
iterator it_end() {
return iterator(map_m,NULL);
}
// overload operator, need not be deep copy
iterator& operator=(const iterator& x) {
map_m = x.map_m;
node_m = x.node_m;
return *this;
}
// overload comparison operator
bool operator==(const iterator& x) {
return node_m == x.node_m;
}
bool operator!=(const iterator& x) {
return node_m != x.node_m;
}
reference operator*() {
if (node_m == NULL) {
pair<const Key,T> m = make_pair(Key(),T());
node_m = new node_t(m);
}
return node_m -> value_m;
}
pointer operator->() {
if (node_m == NULL) {
pair<const Key,T> m = make_pair(Key(),T());
node_m = new node_t(m);
}
return &(node_m -> value_m);
}
iterator operator++() {
node_m = map_m -> _successor(node_m);
return *this;
}
iterator operator++(int) {
iterator ret(*this);
node_m = map_m -> _successor(node_m);
return ret;
}
// data members in the iterator class
private:
// iterator need to know which node it is pointing to
bstmap* map_m;
node_t* node_m;
};
class const_iterator {
typedef std::input_iterator_tag iterator_category;
typedef const pair<const Key,T> value_type;
typedef value_type* pointer;
typedef value_type& reference;
friend class iterator;
friend class bstmap;
public:
// default constructor of const_iterator
const_iterator(bstmap* map,node_t* node) : map_m(map_m), node_m(node) {}
// copy constructor of const_iterator
const_iterator(const const_iterator& x) : map_m(x.map_m), node_m(x.node_m) {}
const_iterator(const iterator& x) : map_m(x.map_m), node_m(x.node_m) {}
const_iterator it_begin() {
node_t* result = NULL;
while (node_m != NULL) {
result = node_m;
node_m = node_m -> left_m;
}
return const_iterator(map_m,result);
}
const_iterator it_end() {
return iterator(map_m,NULL);
}
const_iterator& operator=(const const_iterator& x) {
map_m = x.map_m;
node_m = x.node_m;
return *this;
}
bool operator==(const const_iterator& x) {
return node_m == x.node_m;
}
bool operator!=(const const_iterator& x) {
return node_m != x.node_m;
}
reference operator*() {
if (node_m == NULL) {
const pair<const Key,T> m = make_pair(Key(),T());
node_m = new node_t(m);
}
return node_m -> value_m;
}
pointer operator->() {
if (node_m == NULL) {
const pair<const Key,T> m = make_pair(Key(),T());
node_m = new node_t(m);
}
return &(node_m -> value_m);
}
const_iterator operator++() {
node_m = map_m -> _successor(node_m);
return *this;
}
const_iterator operator++(int) {
const_iterator ret(*this);
node_m = map_m -> _successor(node_m);
return ret;
}
private:
bstmap* map_m;
node_t* node_m;
};
// implementation of member functions in bstmap
public:
// overload assignment operator, need to do deep copy
Self& operator=(const bstmap<Key,T>& x) {
clear();
root_m = _copy(x.root_m);
return *this;
}
// return the left_most leaf in the tree structure
iterator begin() {
iterator it_ret(this,root_m);
return it_ret.it_begin();
}
const_iterator begin() const {
const_iterator it_ret(this,root_m);
return it_ret.it_begin();
}
iterator end() {
iterator it_ret(this,root_m);
return it_ret.it_end();
}
const_iterator end() const {
const_iterator it_ret(this,root_m);
return it_ret.it_end();
}
bool empty() const {
if (this->size() == 0) return true;
else return false;
}
size_type size() const {
return size_m;
}
// the insert function
pair<iterator,bool> insert(const pair<const Key, T>& x) {
// case 1: if the tree is empty now, take x as the empty node
if (root_m == NULL) {
root_m = new node_t(x);
size_m += 1;
return make_pair(iterator(this,root_m),true);
}
// then try to find whether the key is inserted
pair<node_t*,bool> m = _find(x.first);
if (m.second) {
// if the equivalent key exists
return make_pair(iterator(this,m.first),false);
} else {
// else we can insert it
node_t* new_node = new node_t(x);
// compare two key , x.first is the new_node's key
// m.first->value_m.first is the closest parent key
if (x.first > (m.first -> value_m).first) {
new_node -> parent_m = m.first;
(m.first) -> right_m = new_node;
size_m += 1;
return make_pair(iterator(this,new_node),true);
} else {
new_node -> parent_m = m.first;
(m.first) -> left_m = new_node;
size_m += 1;
return make_pair(iterator(this,new_node),true);
}
}
}
// the erase function
void erase(iterator pos) {
node_t* target_node = pos.node_m;
if (target_node == NULL) return;
if (target_node -> right_m == NULL && target_node -> left_m == NULL) {
node_t* parent_node = target_node -> parent_m;
// when the target node has parent node
if (parent_node != NULL) {
if (parent_node -> left_m == target_node) {
parent_node -> left_m = NULL;
size_m -= 1;
} else {
parent_node -> right_m = NULL;
size_m -= 1;
}
}
// the target_node is a single node in this tree
else {
root_m = NULL;
size_m -= 1;
}
} else if (target_node -> right_m != NULL && target_node -> left_m != NULL){
node_t* y = _successor(target_node);
node_t* z = target_node;
_swap_node(y,z);
if (z->right_m == NULL) {
node_t* parent_node = z->parent_m;
parent_node -> left_m = NULL;
size_m -= 1;
} else {
node_t* parent_node = z -> parent_m;
node_t* changed_node = z -> right_m;
parent_node -> left_m = changed_node;
z -> parent_m = NULL;
z -> right_m = NULL;
size_m -= 1;
}
} else {
node_t* parent_node = target_node -> parent_m;
node_t* changed_node = (target_node -> right_m == NULL) ? target_node -> left_m : target_node -> right_m;
if (parent_node == NULL) {
// erase a root node which has one child
size_m -= 1;
root_m = changed_node;
changed_node -> parent_m = NULL;
} else if (parent_node -> left_m == target_node) {
parent_node -> left_m = changed_node;
changed_node -> parent_m = parent_node;
size_m -= 1;
} else if (parent_node -> right_m == target_node) {
parent_node -> right_m = changed_node;
changed_node -> parent_m = parent_node;
size_m -= 1;
}
}
}
size_type erase(const Key& x) {
pair<node_t*, bool> m = _find(x);
if (m.second) {
node_t* target_node = m.first;
iterator it(this,target_node);
this->erase(it);
return 1;
} else {
return 0;
}
}
void clear() {
_recursive_destroy(root_m);
root_m = NULL;
size_m = 0;
}
iterator find(const Key& x) {
pair<node_t*, bool> m = _find(x);
if (m.second) {
return iterator(this,m.first);
} else {
return iterator(this,NULL);
}
}
const_iterator find(const Key& x) const {
pair<node_t*, bool> m = _find(x);
if (m.second) {
return iterator(this,m.first);
} else {
return iterator(this,NULL);
}
}
size_type count(const Key& x) const {
pair<node_t*, bool> m = _find(x);
if (m.second) return 1;
else return 0;
}
T& operator[](const Key& k) {
pair<node_t*, bool> m = _find(k);
if (m.second) {
return (m.first -> value_m).second;
} else {
this->insert(make_pair(k,T()));
pair<node_t*, bool> n = _find(k);
return (n.first -> value_m).second;
}
// whether insert or not?
}
private:
void _recursive_destroy(node_t* node_m) {
if (node_m == NULL) return;
if (node_m -> left_m != NULL) {
_recursive_destroy(node_m->left_m);
node_m -> left_m = NULL;
}
if (node_m -> right_m != NULL) {
_recursive_destroy(node_m->right_m);
node_m -> right_m = NULL;
}
node_t* parent_node = node_m -> parent_m;
if (parent_node != NULL) {
if (parent_node -> left_m == node_m) {
parent_node -> left_m = NULL;
} else {
parent_node -> right_m = NULL;
}
}
node_m = NULL;
}
// swap function
void _swap_node(node_t* node1, node_t* node2) {
node_t* parent1_tmp = node1 -> parent_m;
node_t* left1_tmp = node1 -> left_m;
node_t* right1_tmp = node1 -> right_m;
node_t* parent2_tmp = node2 -> parent_m;
node_t* left2_tmp = node2 -> left_m;
node_t* right2_tmp = node2 -> right_m;
node_t* node_2 = node2;
if (parent1_tmp -> left_m == node1) {
parent1_tmp -> left_m = node2;
} else {
parent1_tmp -> right_m = node2;
}
node2 -> left_m = left1_tmp;
node2 -> right_m = right1_tmp;
if (parent2_tmp -> left_m = node_2) {
parent2_tmp -> left_m = node1;
} else {
parent2_tmp -> right_m = node1;
}
node1 -> left_m = left2_tmp;
node1 -> right_m = right2_tmp;
}
// here is a copy function for deep_copy
// avoid shallow copy for improper destruction
node_t* _copy(node_t* node_m) {
if (node_m == NULL) return NULL;
node_t* new_node = new node_t(node_m->value_m);
new_node -> left_m = _copy(node_m->left_m);
if (new_node -> left_m != NULL) {
new_node -> left_m -> parent_m = new_node;
}
new_node -> right_m = _copy(node_m->right_m);
if (new_node -> right_m != NULL) {
new_node -> right_m -> parent_m = new_node;
}
return new_node;
}
// here is the function to find the successor
node_t* _successor(node_t* ele) const {
// result node
node_t* result = NULL;
if (ele != NULL) {
// if the child has a right subtree, the leftmost element in the right subtree
if (ele -> right_m != NULL) {
node_t* tmp = ele->right_m;
node_t* tmp_left = tmp->left_m;
while (tmp_left != NULL) {
tmp = tmp_left;
tmp_left = tmp->left_m;
}
result = tmp;
} else {
// check if it is the left child of a node
node_t* parent = ele -> parent_m;
if (parent != NULL) {
if (parent -> left_m == ele) {
result = parent;
} else {
while (parent != NULL && (parent -> right_m == ele)) {
ele = parent;
parent = parent -> parent_m;
}
result = parent;
}
}
}
}
return result;
}
// here is the find function
pair<node_t*, bool> _find(const Key& x) const {
node_t* curr_parent = NULL;
node_t* curr = root_m;
pair<node_t*, bool> result = make_pair(curr,false);
while (curr != NULL) {
curr_parent = curr;
if (x < curr->value_m.first) {
curr = curr->left_m;
} else if (x > curr->value_m.first) {
curr = curr->right_m;
} else {
result.first = curr;
result.second = true;
return result;
}
result.first = curr_parent;
}
return result;
}
private:
// data member in the bstmap
// root_m is a pointer to the root of the tree_map
node_t* root_m;
// size_m stands for the number of nodes in the tree
size_type size_m;
};
#endif