C++手写模板类+迭代器(map二叉树)

 

有了上一次的经验,这次再来写模板类+迭代器确实是更加得心应手了许多,不过这个里面的问题也比上次的复杂了一些,因为涉及到了排序,和左右子树的链接,除此之外也没有什么好说的了,有问题可以留言

bidirectional_map.h (完整版+注释)

#include <iostream>
#include <utility>
#include <vector>
#include <queue>
#include <stack>
using namespace std;

// 节点类
template<class T1, class T2>
class Node {
public:
	pair<T1, T2> val;
	Node<T2, T1>*link;
	Node<T1, T2>*left, *right, *parent;
	Node() :link(NULL), left(NULL), right(NULL), parent(NULL) {}
	Node(const pair<T1, T2> init) :val(init), link(NULL), left(NULL), right(NULL), parent(NULL) {}
};


// map的迭代器类
template<class T1, class T2>
class map_iterator {
public:
	// ptr_ 表示当前节点, root_为辅助节点记录了根节点
	Node<T1, T2>*ptr_, *root_;
	map_iterator() : ptr_(NULL), root_(NULL) {}
	// 根据用于初始化的节点直接找到根节点,就不用多传入一个参数
	map_iterator(Node<T1, T2> *init) {
		ptr_ = init;
		root_ = init;
		while (root_!=NULL && root_->parent!=NULL)
			root_ = root_->parent;
	}
	~map_iterator() { ptr_ = NULL; root_ = NULL; }
	// 几个基本的符号操作
	map_iterator& operator=(const map_iterator& old) { ptr_ = old.ptr_; root_ = old.root_; return *this; }
	pair<T1, T2>& operator*() const { return ptr_->val; }
	friend bool operator== (const map_iterator& lft, const map_iterator& rgt) {
		return lft.ptr_ == rgt.ptr_;
	}
	friend bool operator!= (const map_iterator& lft, const map_iterator& rgt) {
		return lft.ptr_ != rgt.ptr_;
	}
	// 树形结构没有明显的线性结构,所以需要较为复杂的操作来进行前移和后移
	// 画图模拟更直观
	// 重载迭代器后移
	map_iterator & operator++() {
		// 当前节点右孩子的最左端点,就是当前节点的后一个节点
		if (ptr_->right != NULL) {
			ptr_ = ptr_->right;
			while (ptr_->left != NULL) {
				ptr_ = ptr_->left;
			}
		}
		// 当前节点没有右孩子,说明已经走到底部,需要往上回溯到这条直链的最左端
		// 他的父亲节点就是最右下端点的后一个节点
		else {
			while (ptr_->parent != NULL && ptr_->parent->right == ptr_) {
				ptr_ = ptr_->parent;
			}
			ptr_ = ptr_->parent;
		}
		return *this;
	}
	map_iterator operator++(int) {
		map_iterator tmp(*this);
		++(*this);
		return tmp;
	}
	// 重载前移操作
	map_iterator& operator--() {
		// 当前节点不是根节点或空节点、尾节点
		if (ptr_ && ptr_->parent) {
			// 是叶子节点
			if (!(ptr_->right) && !(ptr_->left)) {
				// 当前节点为上一个节点的右孩子,说明前一个节点就是上一个
				if (ptr_ == ptr_->parent->right)
					ptr_ = ptr_->parent;
				// 当前节点为上一个节点的左孩子
				else if (ptr_ == ptr_->parent->left) {
					// 如果这个节点还有左孩子,那这个左孩子是上一个
					if (ptr_->left)
						ptr_ = ptr_->left;
					// 如果没有左孩子了,那前一个节点就是这条直链最左端的父亲节点
					else {
						while (ptr_->parent != NULL && ptr_->parent->left == ptr_)
							ptr_ = ptr_->parent;
						ptr_ = ptr_->parent;
					}
				}
			}
			// 如果不是叶子节点
			else {
				// 左孩子的第一个右孩子就是上一个
				if (ptr_->left) {
					ptr_ = ptr_->left;
					while (ptr_->left && !(ptr_->right))
						ptr_ = ptr_->left;
					if (ptr_->right)
						ptr_ = ptr_->right;
				}
				else if (ptr_->right)
					ptr_ = ptr_->parent;
			}
		}
		// 如果是根节点
		else if (ptr_ && !(ptr_->parent)) {
			// 它的上一个只能是左孩子的最右孩子
			if (ptr_->left) {
				ptr_ = ptr_->left;
				while (ptr_->right)
					ptr_ = ptr_->right;
			}
		}
		// 如果是尾节点,那只需要找到这棵树的最后一个节点
		else {
			ptr_ = root_;
			while (ptr_->right)
				ptr_ = ptr_->right;
		}
		return *this;
	}
	map_iterator operator--(int) {
		map_iterator tmp(*this);
		--(*this);
		return tmp;
	}
	// 起始节点就是最左节点
	map_iterator& begin() {
		ptr_ = root_;
		while (ptr_&&ptr_->left)
			ptr_ = ptr_->left;
		return *this;
	}
	// 尾节点就是一个空节点
	map_iterator& end() {
		ptr_ = NULL;
		return *this;
	}
	// 链接到隔壁树上的同一个
	map_iterator<T2, T1> follow_link() { return map_iterator<T2, T1>(ptr_->link); }
};

// map类
template<class T1, class T2>
class bidirectional_map {
private:
	// 键在前的子树
	Node<T1, T2>*key_root;
	// 值在前的反向子树
	Node<T2, T1>*value_root;
	// 树的容量
	int size_;
public:
	// 键迭代器
	typedef map_iterator<T1, T2> key_iterator;
	friend class map_iterator<T1, T2>;
	// 值迭代器
	typedef map_iterator<T2, T1> value_iterator;
	friend class map_iterator<T2, T1>;
	bidirectional_map() :key_root(NULL), value_root(NULL), size_(0) {}
	// 复制构造函数
	bidirectional_map(bidirectional_map& old) : size_(0) {
		copy_tree(old);
	}
	// 重载赋值操作符
	bidirectional_map& operator=(bidirectional_map& old) {
		// 如果要赋值的这两个map不一样
		// 则先删除原map中的数据再把新数据覆盖进去
		if (&old != this) {
			size_ = 0;
			broke(key_root);
			broke(value_root);
			copy_tree(old);
		}
		return *this;
	}
	// 复制函数
	void copy_tree(bidirectional_map &old) {
		key_root = NULL;
		value_root = NULL;
		for (key_iterator ki = old.key_begin(); ki != old.key_end(); ki++)
			insert((*ki));
	}
	// 容量函数
	int size() { return size_; }
	// 键树起点
	key_iterator key_begin() { return key_iterator(key_root).begin(); }
	key_iterator key_end() { return key_iterator(key_root).end(); }
	// 值树起点
	value_iterator value_begin() { return value_iterator(value_root).begin(); }
	value_iterator value_end() { return value_iterator(value_root).end(); }
	// 删除两子树并把容量清空
	~bidirectional_map() {
		broke(key_root);
		broke(value_root);
		size_ = 0;
	}
	// 根据键和值的大小,插入两棵排序树中
	// 返回值为插入元素的迭代器和是否成功插入
	pair<key_iterator, bool> insert(pair<T1, T2> const& key) {
		Node<T1, T2>*kt = key_root;
		Node<T2, T1>*vt = value_root;
		if(key_root)
			while (1) {
				if (key.first < kt->val.first) {
					if (kt->left)
						kt = kt->left;
					else
						break;
				}
				else if (key.first > kt->val.first) {
					if (kt->right)
						kt = kt->right;
					else
						break;
				}
				else {
					return make_pair(key_iterator(kt), false);
				}
			}
		Node<T1, T2>*key_ = new Node<T1, T2>(key);
		Node<T2, T1>*val_ = new Node<T2, T1>(make_pair(key.second, key.first));
		key_->link = val_;
		val_->link = key_;
		if (key_root == NULL && value_root == NULL) {
			key_root = key_;
			value_root = val_;
		}
		else {
			while (1) {
				if (key.first < kt->val.first) {
					if (kt->left)
						kt = kt->left;
					else {
						key_->parent = kt;
						kt->left = key_;
						break;
					}
				}
				else if (key.first > kt->val.first) {
					if (kt->right)
						kt = kt->right;
					else {
						key_->parent = kt;
						kt->right = key_;
						break;
					}
				}
			}
			while (1) {
				if (key.second < vt->val.first) {
					if (vt->left)
						vt = vt->left;
					else {
						val_->parent = vt;
						vt->left = val_;
						break;
					}
				}
				else if (key.second > vt->val.first) {
					if (vt->right)
						vt = vt->right;
					else {
						val_->parent = vt;
						vt->right = val_;
						break;
					}
				}
			}
		}
		size_++;
		return make_pair(key_iterator(key_), true);
	}
	// 根据深度打印出两棵树的形状
	void print(ostream& ostr) {
		ostr << "=================================================" << endl;
		ostr << "KEYS:" << endl;
		out(ostr, key_root, 0);
		ostr << "-------------------------------------------------" << endl;
		ostr << "VALUES:" << endl;
		out(ostr, value_root, 0);
		ostr << "=================================================" << endl;
	}
	// 用中序遍历递归的方法遍历并打印树
	void out(ostream& ostr, Node<T1, T2>* k, int deep) {
		if (!k)
			return;
		out(ostr, k->right, deep + 1);
		for (int i = 0; i < deep; i++) ostr << "  ";
		ostr << k->val.first << " [" << k->val.second << "]" << endl;
		out(ostr, k->left, deep + 1);
	}
	void out(ostream& ostr, Node<T2, T1>* k, int deep) {
		if (!k)
			return;
		out(ostr, k->right, deep + 1);
		for (int i = 0; i < deep; i++) ostr << "  ";
		ostr << k->val.first << " [" << k->val.second << "]" << endl;
		out(ostr, k->left, deep + 1);
	}
	// 用后序遍历递归进行遍历然后删除树
	void broke(Node<T1, T2>* key) {
		if (!key)
			return;
		broke(key->left);
		broke(key->right);
		delete key;
		key = NULL;
	}
	void broke(Node<T2, T1>* val) {
		if (!val)
			return;
		broke(val->left);
		broke(val->right);
		delete val;
		val = NULL;
	}
	// 重载【】号,用二分法快速找到需要的目标
	T2 operator[](T1 key) {
		Node<T1, T2>*p = key_root;
		while (p) {
			if (key == p->val.first)
				return p->val.second;
			else if (key > p->val.first)
				p = p->right;
			else
				p = p->left;
		}
		return T2();
	}
	T1 operator[](T2 val) {
		Node<T2, T1>*p = value_root;
		while (p) {
			if (val == p->val.first)
				return p->val.second;
			else if (val > p->val.first)
				p = p->right;
			else
				p = p->left;
		}
		return T1();
	}
	// 用二分法查找map中元素
	key_iterator find(T1 key) {
		Node<T1, T2> *p = key_root;
		while (p) {
			if (key == p->val.first)
				return key_iterator(p);
			else if (key > p->val.first)
				p = p->right;
			else
				p = p->left;
		}
		return key_end();
	}
	value_iterator find(T2 val) {
		Node<T2, T1> *p = value_root;
		while (p) {
			if (val == p->val.first)
				return value_iterator(p);
			else if (val > p->val.first)
				p = p->right;
			else
				p = p->left;
		}
		return value_end();
	}
	// 先根据键从键树中找出要删除的元素的身份
	int erase(T1 key) {
		Node<T1, T2>*p = key_root;
		while (p) {
			if (key == p->val.first) {
				Node<T2, T1>*q = p->link;
				q->link = NULL;
				p->link = NULL;
				erase(p->val.second, q);
				erase(key, p);
				size_--;
				return 1;
			}
			else if (key > p->val.first)
				p = p->right;
			else
				p = p->left;
		}
		return 0;
	}

	// 若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树
	// 由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点

	// 若*p结点只有左子树PL或右子树PR
	// 此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可
	// 作此修改也不破坏二叉排序树的特性。
		
	// 若*p结点的左子树和右子树均不空
	// 在删去*p之后,为保持其它元素之间的相对位置不变
	// 令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树
	// *s为*p左子树的最右下的结点,而*p的右子树为*s的右子树
	void erase(T1 k, Node<T1, T2>*&key) {
		if (!key)
			return;
		if (k > key->val.first)
			erase(k, key->right);
		else if (k < key->val.first)
			erase(k, key->left);
		else {
			Node<T1, T2> *p;
			if (key->left && key->right) {
				p = key->left;
				while (p->right)
					p = p->right;
				key->val = p->val;
				erase(p->val.first, p);
			}
			else if (key->left) {
				p = key->left;
				if (!key->parent)
					key_root = p;
				else if (key == key->parent->left)
					key->parent->left = p;
				else
					key->parent->right = p;
				// delete key;
				key = NULL;
			}
			else if (key->right) {
				p = key->right;
				if (!key->parent)
					key_root = p;
				else if (key == key->parent->left)
					key->parent->left = p;
				else
					key->parent->right = p;
				// delete key;
				key = NULL;
			}
			else {
				p = key;
				if (p->parent) {
					if (p == p->parent->left) {
						p->parent->left = NULL;
						// delete p;
						p = NULL;
					}
					else {
						p->parent->right = NULL;
						// delete p;
						p = NULL;
					}
				}
				else {
					key = NULL;
					// delete p;
					p = NULL;
				}
			}
		}
	}
	void erase(T2 k, Node<T2, T1> *&val) {
		if (!val)
			return;
		if (k > val->val.first)
			erase(k, val->right);
		else if (k < val->val.first)
			erase(k, val->left);
		else {
			Node<T2, T1> *p;
			if (val->left && val->right) {
				p = val->left;
				while (p->right)
					p = p->right;
				val->val = p->val;
				erase(p->val.first, p);
			}
			else if (val->left) {
				p = val->left;
				if (!val->parent)
					value_root = p;
				else if (val == val->parent->left)
					val->parent->left = p;
				else
					val->parent->right = p;
				// delete val;
				val = NULL;
			}
			else if (val->right) {
				p = val->right;
				if (!val->parent)
					value_root = p;
				else if (val == val->parent->left)
					val->parent->left = p;
				else
					val->parent->right = p;
				// delete val;
				val = NULL;
			}
			else {
				p = val;
				if (p->parent) {
					if (p == p->parent->left) {
						p->parent->left = NULL;
						// delete p;
						p = NULL;
					}
					else {
						p->parent->right = NULL;
						// delete p;
						p = NULL;
					}
				}
				else {
					val = NULL;
					// delete p;
					p = NULL;
				}
			}
		}
	}
};

main.cpp (用于测试)

// ===================================================================
//
// IMPORTANT: Do not make any changes to this file, except to
//            uncomment the test cases in BasicTests and
//            ExtraCreditTests as you work, and to write your own test
//            cases in StudentTests.
//
// ===================================================================

#include <iostream>
#include <cassert>
#include <string>
#include <vector> 
#include <utility>
#include <algorithm>
#include <cstdlib>

#include "bidirectional_map.h"


// prototypes of helper functions
void BasicTests();
void StudentTests();
void ExtraCreditTests();


int main() {

  //BasicTests();
  StudentTests();
  ExtraCreditTests();

}


void BasicTests() {

  std::cout << "Beginning BasicTests()..." << std::endl;

  // some simple data to put in the map
  std::vector<std::string> keys;
  std::vector<int> values;
  keys.push_back("carrot");
  keys.push_back("banana");
  keys.push_back("date");
  keys.push_back("fig");
  keys.push_back("eggplant");
  keys.push_back("apple");
  values.push_back(4);
  values.push_back(5);
  values.push_back(6);
  values.push_back(2);
  values.push_back(1);
  values.push_back(3);

  // sorted versions of the input data for testing the iterators
  std::vector<std::string> sorted_keys = keys;
  std::sort(sorted_keys.begin(),sorted_keys.end());
  std::vector<int> sorted_values = values;
  std::sort(sorted_values.begin(),sorted_values.end());


  // ------------------------------------------------
  // CREATE A BIDIRECTIONAL MAP
  bidirectional_map<std::string,int> bdmap;
  assert (bdmap.size() == 0);


  // INSERT 6 SIMPLE ONE-TO-ONE ASSOCIATIONS
  // (a later test case will verify the return value of insert)
  for (int i = 0; i < 6; i++) {
    bdmap.insert(std::make_pair(keys[i],values[i])); 
  }
  assert (bdmap.size() == 6);


  // PRINT THE STRUCTURE 
  // note the formatting of this output is not strictly specified, 
  // but the data should be clearly presented
  std::cout << "created bidirectional map with 6 associations" << std::endl;
  bdmap.print(std::cout);


  // ------------------------------------------------
  
  // TEST THE SUBSCRIPT [] OPERATOR
  // verify that the associations are bidirectional
  for (int i = 0; i < 6; i++) {
    assert (bdmap[keys[i]] == values[i]);
    assert (bdmap[values[i]] == keys[i]);
  }
  std::cout << "bidirectional links verified" << std::endl;
  


  // ------------------------------------------------
  
  // TEST FIND ON KEYS
  bidirectional_map<std::string,int>::key_iterator ki; 
  for (int i = 0; i < 6; i++) {
    ki = bdmap.find(keys[i]);
    assert (ki != bdmap.key_end());
    assert ((*ki).first == keys[i]);
    assert ((*ki).second == values[i]);
  }
  ki = bdmap.find("grape");
  assert (ki == bdmap.key_end());
  // TEST FIND ON VALUES
  bidirectional_map<std::string,int>::value_iterator vi;
  for (int i = 0; i < 6; i++) {
    vi = bdmap.find(values[i]);
    assert (vi != bdmap.value_end());
    assert ((*vi).first == values[i]);
    assert ((*vi).second == keys[i]);
  }
  vi = bdmap.find(7);
  assert (vi == bdmap.value_end());
  std::cout << "find on keys and find on values successful" << std::endl;
  


  // ------------------------------------------------
    
  // FORWARD ITERATOR ON KEYS
  int counter = 0;
  for (bidirectional_map<std::string,int>::key_iterator ki = bdmap.key_begin();
       ki != bdmap.key_end(); ki++) {
    assert (sorted_keys[counter] == (*ki).first);
    std::cout << "key:" << (*ki).first << " associated with value:" << (*ki).second << std::endl;
    counter++;
  }
  // FORWARD ITERATOR ON VALUES
  counter = 0;
  for (bidirectional_map<std::string,int>::value_iterator vi = bdmap.value_begin();
       vi != bdmap.value_end(); vi++) {
    assert (sorted_values[counter] == (*vi).first);
    std::cout << "value:" << (*vi).first << " associated with key:" << (*vi).second << std::endl;
    counter++;
  }
  // BACKWARD ITERATOR ON KEYS
  counter = 5;
  ki = bdmap.find(sorted_keys[counter]);
  while (1) {
    assert ((*ki).first == sorted_keys[counter]);
    if (counter == 0) break;
    counter--;
    ki--;
  }
  // BACKWARD ITERATOR ON VALUES
  counter = 5;
  vi = bdmap.find(sorted_values[counter]);
  while (1) {
    assert ((*vi).first == sorted_values[counter]);
    if (counter == 0) break;
    counter--;
    vi--;
  }
  std::cout << "forward and backward iterators on keys and values successful" << std::endl;
  


  // ------------------------------------------------
  // TESTING THE RETURN VALUE OF INSERT
  // like the STL map, insert returns a pair with an iterator pointing
  // to the key in the map, and a bool indicating whether the element
  // was newly added, or was already there
  
  std::pair<bidirectional_map<std::string,int>::key_iterator,bool> insert_return;
  insert_return = bdmap.insert(std::make_pair("zebra",26));
  assert (insert_return.first == bdmap.find("zebra"));
  assert (insert_return.second == true);
  insert_return = bdmap.insert(std::make_pair("apple",3));
  assert (insert_return.first == bdmap.find("apple"));
  assert (insert_return.second == false);
  assert (bdmap.size() == 7);
  bdmap.print(std::cout);
  std::cout << "return value of insert correct" << std::endl;
  


  // ------------------------------------------------
  // ERASE KEY-VALUE ASSOCIATIONS FROM THE STRUCTURE
  // erase returns an integer, indicating whether the specified key
  // exists in the structure and was successfully erased
  
  assert (bdmap.size() == 7);
  int num_erased = bdmap.erase("zebra");
  assert (num_erased == 1);
  assert (bdmap.size() == 6);
  bdmap.print(std::cout);
  std::cout << "erased key:'zebra' and value:26" << std::endl;
  num_erased = bdmap.erase("carrot");
  assert (num_erased == 1);
  assert (bdmap.size() == 5);
  bdmap.print(std::cout);
  std::cout << "erased key:'carrot' and value:4" << std::endl;
  num_erased = bdmap.erase("date");
  assert (num_erased == 1);
  assert (bdmap.size() == 4);
  bdmap.print(std::cout);
  std::cout << "erased key:'date' and value:6" << std::endl;
  num_erased = bdmap.erase("grape");
  assert (num_erased == 0);
  std::cout << "erase tests valid" << std::endl;
  


  // ------------------------------------------------
  // MORE TESTING OF THE RETURN VALUE OF INSERT
  
  insert_return = bdmap.insert(std::make_pair("carrot",6));
  assert (insert_return.first == bdmap.find("carrot"));
  assert (insert_return.second == true);
  insert_return = bdmap.insert(std::make_pair("apple",3));
  assert (insert_return.first == bdmap.find("apple"));
  assert (insert_return.second == false);
  assert (bdmap.size() == 5);
  bdmap.print(std::cout);
  std::cout << "return value of insert correct" << std::endl;
  

  
  // ------------------------------------------------
  // TESTING THE FOLLOW_LINK FUNCTION
  // the follow link function can be used to "jump" from an iterator
  // on keys tree, to an iterator in the values tree (and vice versa)
  
  ki = bdmap.find("fig");
  assert (ki != bdmap.key_end());
  assert ((*ki).first == "fig");
  assert ((*ki).second == 2);
  vi = ki.follow_link();
  assert (vi != bdmap.value_end());
  assert ((*vi).first == 2);
  assert ((*vi).second == "fig");
  bidirectional_map<std::string,int>::key_iterator ki2 = vi.follow_link();
  assert (ki == ki2);
  std::cout << "follow link function successful" << std::endl;
  

  
  std::cout << "BasicTests() completed" << std::endl;
}


void StudentTests() {

  std::cout << "Beginning StudentTests()..." << std::endl;   

  //
  // Add your own test cases here
  //
  // Be sure to test:
  //   * copy constructor
  //   * assignment operator
  //   * bidirectional_maps with other data types
  //   * all corner cases of insert, find, and erase
  //
  int num[] = { 8, 4, 12, 2, 1, 3, 6, 5, 7, 10, 9, 11, 14, 13, 15 };
  char fu[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' };
  bidirectional_map<char, int> mmap, nmap;
  for (int i = 0; i < 15; i++)
	  mmap.insert(std::make_pair(fu[i], num[i]));
  mmap.print(std::cout);
  nmap = mmap;
  nmap.print(std::cout);
  bidirectional_map<char, int> omap(mmap);
  bidirectional_map<char, int>::key_iterator n_it(nmap.key_begin()), m_it(mmap.key_begin());
  for (; n_it != nmap.key_end() && m_it != mmap.key_end(); n_it++, m_it++) {
	  assert((*n_it) == (*m_it));
  }
  omap.erase('c');
  omap.erase('g');
  omap.erase('m');
  omap.erase('l');
  omap.print(std::cout);
  assert((*omap.find('e')).second == num[4]);
  std::cout << "key:" << (*omap.find('e')).first << " associated with value:" << (*omap.find('e')).second << std::endl;
  omap.insert(std::make_pair('z', 26));
  omap.print(std::cout);

 std::cout << "StudentTests() completed" << std::endl;

}



void ExtraCreditTests() {

/*
  // uncomment if you implement non one-to-one associations
  

  std::cout << "Beginning ExtraCreditTests()..." << std::endl;   


  // these tests illustrate how non one-on-one associations are
  // stored, queried, and removed from the structure


  // some simple data to put in the map
  std::vector<std::string> keys;
  keys.push_back("cat");
  keys.push_back("dog");
  keys.push_back("cat");
  keys.push_back("bird");
  keys.push_back("cat");
  keys.push_back("dog");
  keys.push_back("bird");
  std::vector<int> values;
  values.push_back(4);
  values.push_back(6);
  values.push_back(1);
  values.push_back(6);
  values.push_back(2);
  values.push_back(1);
  values.push_back(1);

  // sorted versions of the input data for testing the iterators
  std::vector<std::string> sorted_keys = keys;
  std::sort(sorted_keys.begin(),sorted_keys.end());
  std::vector<int> sorted_values = values;
  std::sort(sorted_values.begin(),sorted_values.end());


  // ------------------------------------------------  
  // INSERT NON ONE-TO-ONE ASSOCIATIONS
  // insert a number of associations, note that in this example we
  // have duplicates in both keys and values
  bidirectional_map<std::string,int> bdmap;
  for (int i = 0; i < 6; i++) {
    bdmap.insert(std::make_pair(keys[i],values[i]));
  }
  assert (bdmap.size() == 6);
  bdmap.print(std::cout);


  // FAILED INSERT
  // however, when we try to insert an association that is already in
  // the structure the insert returns false
  std::pair<bidirectional_map<std::string,int>::key_iterator,bool> insert_result;
  insert_result = bdmap.insert(std::make_pair("cat", 2));
  assert ((*insert_result.first).first == "cat");
  assert ((*insert_result.first).second == 2);
  assert (insert_result.second == false);
  assert (bdmap.size() == 6);


  // ANOTHER SUCCESSFUL INSERT 
  insert_result = bdmap.insert(std::make_pair(keys[6],values[6]));
  assert (insert_result.first == bdmap.find("bird"));
  assert (insert_result.second == true);
  assert (bdmap.size() == 7);
  bdmap.print(std::cout);
  


  // ------------------------------------------------
  // FORWARD ITERATOR ON KEYS
  std::cout << "forward iteration over keys:" << std::endl;
  unsigned int counter = 0;
  for (bidirectional_map<std::string,int>::key_iterator ki = bdmap.key_begin();
       ki != bdmap.key_end(); ki++) {
    std::cout << "  key:" << (*ki).first << " associated with value:" << (*ki).second << std::endl;
    assert ((*ki).first == sorted_keys[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  // FORWARD ITERATOR ON VALUES
  std::cout << "forward iteration over values:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::value_iterator vi = bdmap.value_begin();
       vi != bdmap.value_end(); vi++) {
    std::cout << "  value:" << (*vi).first << " associated with key:" << (*vi).second << std::endl;
    assert ((*vi).first == sorted_values[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  bdmap.print(std::cout);



  // ------------------------------------------------
  // ERASE AN ASSOCIATION
  // erase a single association between key:cat and value:4
  int num_erased = bdmap.erase("cat", 4);
  bdmap.print(std::cout);
  assert (num_erased == 1);
  assert (bdmap.size() == 6);
  std::cout << "erased key:cat and value:4" << std::endl;
  sorted_keys.erase(sorted_keys.begin()+4);
  sorted_values.erase(sorted_values.begin()+4);

  // verify iteration over keys and values
  std::cout << "forward iteration over keys:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::key_iterator ki = bdmap.key_begin();
       ki != bdmap.key_end(); ki++) {
    std::cout << "  key:" << (*ki).first << " associated with value:" << (*ki).second << std::endl;
    assert ((*ki).first == sorted_keys[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  std::cout << "forward iteration over values:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::value_iterator vi = bdmap.value_begin();
       vi != bdmap.value_end(); vi++) {
    std::cout << "  value:" << (*vi).first << " associated with key:" << (*vi).second << std::endl;
    assert ((*vi).first == sorted_values[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  bdmap.print(std::cout);


  // ------------------------------------------------
  // FAILED ERASE
  // try to erase an association that does not exist
  num_erased = bdmap.erase("bird", 2);
  assert (num_erased == 0);
  assert (bdmap.size() == 6);


  // ------------------------------------------------
  // ERASE ALL WITH SPECIFIC KEY 
  // erase all associations with "dog" as the key
  num_erased = bdmap.erase("dog");
  assert (num_erased == 2);
  assert (bdmap.size() == 4);
  bdmap.print(std::cout);
  std::cout << "erased all key:dog associations" << std::endl;
  sorted_keys.erase(sorted_keys.begin()+5);
  sorted_keys.erase(sorted_keys.begin()+4);
  sorted_values.erase(sorted_values.begin()+5);
  sorted_values.erase(sorted_values.begin()+2);

  // verify iteration over keys and values
  std::cout << "forward iteration over keys:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::key_iterator ki = bdmap.key_begin();
       ki != bdmap.key_end(); ki++) {
    std::cout << "  key:" << (*ki).first << " associated with value:" << (*ki).second << std::endl;
    assert ((*ki).first == sorted_keys[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  std::cout << "forward iteration over values:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::value_iterator vi = bdmap.value_begin();
       vi != bdmap.value_end(); vi++) {
    std::cout << "  value:" << (*vi).first << " associated with key:" << (*vi).second << std::endl;
    assert ((*vi).first == sorted_values[counter]);
    counter++;
  }
  assert (counter == bdmap.size());


  // ------------------------------------------------
  // ERASE ALL WITH SPECIFIC VALUE
  // erase all associations with 1 as the value
  num_erased = bdmap.erase(1);
  assert (num_erased == 2);
  assert (bdmap.size() == 2);
  bdmap.print(std::cout);
  std::cout << "erased all value:1 associations" << std::endl;
  bdmap.print(std::cout);
  sorted_keys.erase(sorted_keys.begin()+2);
  sorted_keys.erase(sorted_keys.begin());
  sorted_values.erase(sorted_values.begin()+1);
  sorted_values.erase(sorted_values.begin());

  // verify iteration over keys and values
  std::cout << "forward iteration over keys:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::key_iterator ki = bdmap.key_begin();
       ki != bdmap.key_end(); ki++) {
    std::cout << "  key:" << (*ki).first << " associated with value:" << (*ki).second << std::endl;
    assert ((*ki).first == sorted_keys[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  std::cout << "forward iteration over values:" << std::endl;
  counter = 0;
  for (bidirectional_map<std::string,int>::value_iterator vi = bdmap.value_begin();
       vi != bdmap.value_end(); vi++) {
    std::cout << "  value:" << (*vi).first << " associated with key:" << (*vi).second << std::endl;
    assert ((*vi).first == sorted_values[counter]);
    counter++;
  }
  assert (counter == bdmap.size());
  */

  std::cout << "ExtraCreditTests() completed" << std::endl;
  

}

正确的测试输出

Beginning BasicTests()...
created bidirectional map with 6 associations
=================================================
KEYS:
        fig [2]
            eggplant [1]
    date [6]
carrot [4]
    banana [5]
        apple [3]
-------------------------------------------------
VALUES:
        6 [date]
    5 [banana]
4 [carrot]
        3 [apple]
    2 [fig]
        1 [eggplant]
=================================================
bidirectional links verified
find on keys and find on values successful
key:apple associated with value:3
key:banana associated with value:5
key:carrot associated with value:4
key:date associated with value:6
key:eggplant associated with value:1
key:fig associated with value:2
value:1 associated with key:eggplant
value:2 associated with key:fig
value:3 associated with key:apple
value:4 associated with key:carrot
value:5 associated with key:banana
value:6 associated with key:date
forward and backward iterators on keys and values successful
=================================================
KEYS:
            zebra [26]
        fig [2]
            eggplant [1]
    date [6]
carrot [4]
    banana [5]
        apple [3]
-------------------------------------------------
VALUES:
            26 [zebra]
        6 [date]
    5 [banana]
4 [carrot]
        3 [apple]
    2 [fig]
        1 [eggplant]
=================================================
return value of insert correct
=================================================
KEYS:
        fig [2]
            eggplant [1]
    date [6]
carrot [4]
    banana [5]
        apple [3]
-------------------------------------------------
VALUES:
        6 [date]
    5 [banana]
4 [carrot]
        3 [apple]
    2 [fig]
        1 [eggplant]
=================================================
erased key:'zebra' and value:26
=================================================
KEYS:
        fig [2]
            eggplant [1]
    date [6]
banana [5]
    apple [3]
-------------------------------------------------
VALUES:
        6 [date]
    5 [banana]
3 [apple]
    2 [fig]
        1 [eggplant]
=================================================
erased key:'carrot' and value:4
=================================================
KEYS:
    fig [2]
        eggplant [1]
banana [5]
    apple [3]
-------------------------------------------------
VALUES:
    5 [banana]
3 [apple]
    2 [fig]
        1 [eggplant]
=================================================
erased key:'date' and value:6
erase tests valid
=================================================
KEYS:
    fig [2]
        eggplant [1]
            carrot [6]
banana [5]
    apple [3]
-------------------------------------------------
VALUES:
        6 [carrot]
    5 [banana]
3 [apple]
    2 [fig]
        1 [eggplant]
=================================================
return value of insert correct
follow link function successful
BasicTests() completed

 

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值