set 和 map: set 和 map 的实现

1. 关联式容器

STL中的部分容器,比如:vector、list、deque、 forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 存储的是元素本身。

那什么是关联式容器?它与序列式容器有什么区别?

关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是结构的 键值对,在数据检索时比序列式容器效率更高。

2. 键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代 表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。

SGI-STL中关于键值对的定义:

template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
};

3. 树形结构的关联式容器

根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结 构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。

迭代器的实现

下面是较为简单的迭代器重载的实现:

	enum color
	{
		BLACK,
		RED,
	};

	template<class v >
	struct RBTNode
	{
		v _kv;
		RBTNode<v>* _left;
		RBTNode<v>* _right;
		RBTNode<v>* _parent;
		color _col;


		RBTNode(const v& key)
			:_kv(key)
			, _left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
		{}
	};

	template<class v, class ref, class ptr>
	struct RBTreeIterator
	{
		typedef RBTNode<v> Node;
		typedef RBTreeIterator<v, ref, ptr> self;

		RBTreeIterator(Node* node, Node* root)
			:_node(node)
			, _root(root)
		{}

		bool operator!= (const self& key)
		{
			return _node != key._node;
		}

		bool operator==(const self& key)
		{
			return _node == key._node;
		}

		ref operator*()
		{
			return _node->_kv;
		}

		ptr operator->()
		{
			return &_node->_kv;
		}

		
		Node* _root;
		Node* _node;
	};

operator++ 的实现

it如果现在在根的位置,++寻找的是右树的最左节点。

如果右树不为空,找到右树最左节点。

右边为空,找孩子是父亲左边的祖先。

		self& operator++()
		{
			if (_node && _node->_right)
			{
				Node* right = _node->_right;
				while (right->_left)
				{
					right = right->_left;
				}
				_node = right;
			}
			else if (_node && _node->_right == nullptr)
			{
				Node* parent = _node->_parent;
				while (parent != nullptr && _node == parent->_right)
				{
					_node = parent;
					parent = _node->_parent;
				}
				_node = parent;
			}
			return *this;
		}

operator--的实现

同样的思路:

it如果现在在根的位置,++寻找的是左树的最右节点。

如果左树不为空,找到左树的最右节点。

左边为空,找孩子是父亲右边的祖先。

如果是end()-- 则需要特殊处理。

		self& operator--()
		{
			if (_node == nullptr)
			{
				Node* right = _root;
				while (right && right->_right)
				{
					right = right->_right;
				}
				_node = right;
			}
			else if (_node->_left)
			{
				Node* left = _node->_left;
				while (left->_right)
				{
					left = left->_right;
				}
				_node = left;
			}
			else
			{
				Node* parent = _node->_parent;
				while (parent != nullptr && _node == parent->_left)
				{
					_node = parent;
					parent = _node->_parent;
				}
				_node = parent;
			}
			return *this;
		}

		Node* _root;
		Node* _node;
	};

 RBTree中begin 和 end 的实现:

	template<class k, class v, class KeyofT>
	class RBTree
	{
		typedef RBTNode<v> Node;
	public:
		typedef RBTreeIterator<v, v&, v*> iterator;
		typedef RBTreeIterator<v, v&, const v*> Constiterator;

		iterator begin()
		{
			Node* root = _root;
			while (root && root->_left)
			{
				root = root->_left;
			}
			return iterator(root, _root);
		}

		Constiterator begin() const
		{
			Node* root = _root;
			while (root && root->_left)
			{
				root = root->_left;
			}
			return Constiterator(root, _root);
		}


		iterator end()
		{
			return iterator(nullptr, _root);
		}


		Constiterator end() const
		{
			return Constiterator(nullptr, _root);
		}



	private:

		Node* _root = nullptr;
	};

 RBTree的整体代码如下:(点击目录中的set可跳过)

#include<iostream>
#include<cassert>

using namespace std;

namespace bit
{
	enum color
	{
		BLACK,
		RED,
	};

	template<class v >
	struct RBTNode
	{
		v _kv;
		RBTNode<v>* _left;
		RBTNode<v>* _right;
		RBTNode<v>* _parent;
		color _col;


		RBTNode(const v& key)
			:_kv(key)
			, _left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
		{}
	};

	template<class v, class ref, class ptr>
	struct RBTreeIterator
	{
		typedef RBTNode<v> Node;
		typedef RBTreeIterator<v, ref, ptr> self;

		RBTreeIterator(Node* node, Node* root)
			:_node(node)
			, _root(root)
		{}

		bool operator!= (const self& key)
		{
			return _node != key._node;
		}

		bool operator==(const self& key)
		{
			return _node == key._node;
		}

		ref operator*()
		{
			return _node->_kv;
		}

		ptr operator->()
		{
			return &_node->_kv;
		}

		self& operator++()
		{
			if (_node && _node->_right)
			{
				Node* right = _node->_right;
				while (right->_left)
				{
					right = right->_left;
				}
				_node = right;
			}
			else if (_node && _node->_right == nullptr)
			{
				Node* parent = _node->_parent;
				while (parent != nullptr && _node == parent->_right)
				{
					_node = parent;
					parent = _node->_parent;
				}
				_node = parent;
			}
			return *this;
		}


		self& operator--()
		{
			if (_node == nullptr)
			{
				Node* right = _root;
				while (right && right->_right)
				{
					right = right->_right;
				}
				_node = right;
			}
			else if (_node->_left)
			{
				Node* left = _node->_left;
				while (left->_right)
				{
					left = left->_right;
				}
				_node = left;
			}
			else
			{
				Node* parent = _node->_parent;
				while (parent != nullptr && _node == parent->_left)
				{
					_node = parent;
					parent = _node->_parent;
				}
				_node = parent;
			}
			return *this;
		}

		Node* _root;
		Node* _node;
	};

	template<class k, class v, class KeyofT>
	class RBTree
	{
		typedef RBTNode<v> Node;
	public:
		typedef RBTreeIterator<v, v&, v*> iterator;
		typedef RBTreeIterator<v, v&, const v*> Constiterator;
		RBTree() = default;
		RBTree(const RBTree& root)
		{
			_root = Copy(root._root);
		}

		~RBTree()
		{
			Destroy(_root);
			_root = nullptr;
		}

		iterator begin()
		{
			Node* root = _root;
			while (root && root->_left)
			{
				root = root->_left;
			}
			return iterator(root, _root);
		}

		Constiterator begin() const
		{
			Node* root = _root;
			while (root && root->_left)
			{
				root = root->_left;
			}
			return Constiterator(root, _root);
		}


		iterator end()
		{
			return iterator(nullptr, _root);
		}


		Constiterator end() const
		{
			return Constiterator(nullptr, _root);
		}

		bool empty()
		{
			return _root == nullptr;
		}

		pair<iterator, bool> Insert(const v& ret)
		{
			if (_root == nullptr)
			{
				_root = new Node(ret);
				_root->_col = BLACK;
				return make_pair(iterator(_root, _root), true);
			}
			Node* prev = nullptr;
			Node* root = _root;
			KeyofT key;
			while (root != nullptr)
			{
				if (key(root->_kv) > key(ret))
				{
					prev = root;
					root = root->_left;
				}
				else if (key(root->_kv) < key(ret))
				{
					prev = root;
					root = root->_right;
				}
				else return make_pair(iterator(root, _root), false);
			}
			Node* cur = new Node(ret);
			cur->_col = RED;
			Node* Curnode = cur;
			if (key(prev->_kv) > key(ret))
			{
				prev->_left = cur;
				cur->_parent = prev;
			}
			else
			{
				prev->_right = cur;
				cur->_parent = prev;
			}

			while (prev && prev->_col == RED)
			{
				Node* grandfather = prev->_parent;
				Node* uncle = nullptr;
				if (grandfather->_left == prev)
				{
					uncle = grandfather->_right;
				}
				else
				{
					uncle = grandfather->_left;
				}

				if (uncle && uncle->_col == RED)
				{
					prev->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					cur = grandfather;
					prev = cur->_parent;
				}
				else if (uncle == nullptr || uncle->_col == BLACK)
				{
					if (cur == prev->_left && grandfather->_left == prev)
					{
						RotetaR(grandfather);
						grandfather->_col = RED;
						prev->_col = BLACK;
					}
					else if (cur == prev->_right && grandfather->_right == prev)
					{
						RotetaL(grandfather);
						grandfather->_col = RED;
						prev->_col = BLACK;
					}
					else if (grandfather->_left == prev && prev->_right == cur)
					{
						RotetaL(prev);
						RotetaR(grandfather);
						grandfather->_col = RED;
						cur->_col = BLACK;
					}
					else if (grandfather->_right == prev && prev->_left == cur)
					{
						RotetaR(prev);
						RotetaL(grandfather);
						grandfather->_col = RED;
						cur->_col = BLACK;
					}
					break;
				}
			}

			_root->_col = BLACK;


			return make_pair(iterator(Curnode, _root), true);
		}

		iterator Find(const k& ret)
		{
			Node* root = _root;
			KeyofT key;
			while (root != nullptr)
			{
				if (key(root->_kv) > ret)
				{
					root = root->_left;
				}
				else if (key(root->_kv) < ret)
				{
					root = root->_right;
				}
				else return iterator(root, _root);
			}
			return end();
		}

		void Inorder()
		{
			inorder(_root);
			cout << endl;
		}



	private:



		void RotetaL(Node* prev)
		{
			Node* right = prev->_right;
			Node* parent = prev->_parent;

			prev->_right = right->_left;
			if (right->_left)
			{
				right->_left->_parent = prev;
			}

			right->_left = prev;
			prev->_parent = right;

			if (parent == nullptr)
			{
				_root = right;
			}
			else
			{
				if (parent->_left == prev)
				{
					parent->_left = right;
				}
				else
				{
					parent->_right = right;
				}

			}
			right->_parent = parent;
		}

		void RotetaR(Node* prev)
		{
			Node* left = prev->_left;
			Node* parent = prev->_parent;

			prev->_left = left->_right;
			if (left->_right)
			{
				left->_right->_parent = prev;
			}

			left->_right = prev;
			prev->_parent = left;

			if (parent == nullptr)
			{
				_root = left;
			}
			else
			{
				if (parent->_left == prev)
				{
					parent->_left = left;
				}
				else
				{
					parent->_right = left;
				}
			}
			left->_parent = parent;

		}

		void inorder(Node* root)
		{
			if (root == nullptr) return;

			inorder(root->_left);
			cout << root->_kv.first << ' ';
			inorder(root->_right);
		}

		Node* Copy(const Node* root)
		{
			if (root == nullptr) return nullptr;

			Node* val = new Node(root->_kv);
			val->_col = root->_col;
			val->_left = Copy(root->_left);
			if (val->_left)
				val->_left->_parent = val;
			val->_right = Copy(root->_right);
			if (val->_right)
				val->_right->_parent = val;
			return val;
		}

		void Destroy(Node* root)
		{
			if (root == nullptr) return;

			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
		}

		Node* _root = nullptr;
	};
}

4. set

4.1 set的特性

set的特性是,所有元素都会根据元素的键值自动被排序。set的元素不像map 那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,实值就是键值。set不允许两个元素有相同的键值。
我们可以通过set的迭代器改变set 的元素值吗?

不行,因为set 元素值就是其键值,关系到set元素的排列规则。如果任意改变set元素值,会严重破坏set 组织。


set拥有与list相同的某些性质:当客户端对它进行元素新增操作(insert)或删除操作(erase)时,操作之前的所有迭代器,在操作完成之后都依然有效。当然,被删除的那个元素的迭代器必然是个例外。
由于 RB-tree 是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的 STLset 即以 RB-tree 为底层机制。又由于 set 所开放的各种操作接口,RB-tree也都提供了,所以几乎所有的 set 操作行为,都只是转调用 RB-tree 的操作行为而已。

总结:

  1.  set是按照一定次序存储元素的容器
  2.  在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  3.  在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行 排序。
  4.  set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对 子集进行直接迭代。
  5.  set在底层是用二叉搜索树(红黑树)实现的。

4.2 set的框架

set的大致框架如下由于insert,empty ,拷贝构造均已经实现稍加改造直接调用即可。

	template<class k>
	class set
	{
	public:

		set() = default;

		set(const set<k>& key)
			:_root(key._root)
		{ }

		pair<iterator, bool> insert(const k& key)
		{
			return _root.Insert(key);
		}

		bool empty()
		{
			return _root.empty();
		}

	private:

        //因为set中的元素不能在容器中修改所以我们第二个模板类型需要加const
		RBTree<k,const k, SetKeyofT> _root;

	};

RBTree的 insert

由于set 和map用的是同一个 RBTree模板 但是它们的key值又不同所以这里我们需要写一个仿函数

如下:

	template<class k>
	class set
	{
		struct SetKeyofT
		{
			const k& operator()(const k& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<k, const k, SetKeyofT>::iterator iterator;
		typedef typename RBTree<k, const k, SetKeyofT>::Constiterator const_iterator;

	private:

		RBTree<k,const k, SetKeyofT> _root;

	};

RBTree的 insert改造后: 

		pair<iterator, bool> Insert(const v& ret)
		{
			if (_root == nullptr)
			{
				_root = new Node(ret);
				_root->_col = BLACK;
				return make_pair(iterator(_root, _root), true);
			}
			Node* prev = nullptr;
			Node* root = _root;
			KeyofT key;
			while (root != nullptr)
			{
				if (key(root->_kv) > key(ret))
				{
					prev = root;
					root = root->_left;
				}
				else if (key(root->_kv) < key(ret))
				{
					prev = root;
					root = root->_right;
				}
				else return make_pair(iterator(root, _root), false);
			}
			Node* cur = new Node(ret);
			cur->_col = RED;
			Node* Curnode = cur;
			if (key(prev->_kv) > key(ret))
			{
				prev->_left = cur;
				cur->_parent = prev;
			}
			else
			{
				prev->_right = cur;
				cur->_parent = prev;
			}

			while (prev && prev->_col == RED)
			{
				Node* grandfather = prev->_parent;
				Node* uncle = nullptr;
				if (grandfather->_left == prev)
				{
					uncle = grandfather->_right;
				}
				else
				{
					uncle = grandfather->_left;
				}

				if (uncle && uncle->_col == RED)
				{
					prev->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					cur = grandfather;
					prev = cur->_parent;
				}
				else if (uncle == nullptr || uncle->_col == BLACK)
				{
					if (cur == prev->_left && grandfather->_left == prev)
					{
						RotetaR(grandfather);
						grandfather->_col = RED;
						prev->_col = BLACK;
					}
					else if (cur == prev->_right && grandfather->_right == prev)
					{
						RotetaL(grandfather);
						grandfather->_col = RED;
						prev->_col = BLACK;
					}
					else if (grandfather->_left == prev && prev->_right == cur)
					{
						RotetaL(prev);
						RotetaR(grandfather);
						grandfather->_col = RED;
						cur->_col = BLACK;
					}
					else if (grandfather->_right == prev && prev->_left == cur)
					{
						RotetaR(prev);
						RotetaL(grandfather);
						grandfather->_col = RED;
						cur->_col = BLACK;
					}
					break;
				}
			}

			_root->_col = BLACK;


			return make_pair(iterator(Curnode, _root), true);
		}

set的整体代码如下:

#include"RBTree.h"


namespace bit
{
	template<class k>
	class set
	{
		struct SetKeyofT
		{
			const k& operator()(const k& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<k, const k, SetKeyofT>::iterator iterator;
		typedef typename RBTree<k, const k, SetKeyofT>::Constiterator const_iterator;
		set() = default;

		set(const set<k>& key)
			:_root(key._root)
		{ }

		pair<iterator, bool> insert(const k& key)
		{
			return _root.Insert(key);
		}

		iterator begin()
		{
			return _root.begin();
		}

		const_iterator begin()const
		{
			return _root.begin();
		}

		iterator end()
		{
			return _root.end();
		}

		const_iterator end()const
		{
			return _root.end();
		}


		iterator find(const k& key)
		{
			return _root.Find(key);
		}

		bool empty()
		{
			return _root.empty();
		}

	private:

		RBTree<k,const k, SetKeyofT> _root;

	};
}

void testset()
{
	bit::set<int> s1;
	int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	//int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	//int arr[] = { 4, 2, 6,5,7 ,1, 3 };

	for (auto e : arr)
	{
		s1.insert(e);
	}

	for (auto s : s1)
	{
		cout << s << " ";
	}

	cout << endl;
	auto it1 = s1.end();
	while (it1 != s1.begin())
	{
		--it1;
		cout << *it1 << " ";
	}
	cout << endl;
	for (auto e : arr)
	{
		it1 = s1.find(e);
		cout << *it1 << " ";
	}

}

5. map

5.1map的特性:

map的特性是,所有元素都会根据元素的键值自动被排序。map的所有元素都是 pair,同时拥有实值(value)和键值(key)。pair的第一元素被视为键值第二元素被视为实值。map不允许两个元素拥有相同的键值。

  1.  map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。
  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair: typedef pair value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4.  map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5.  map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  6.  map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

5.2 map的框架

namespace bit
{
	template<class k, class T>
	class map
	{
		struct MapKeyofT
		{
			const k& operator()(const pair<k, T>& key)
			{
				return key.first;
			}
		};


	public:
		typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::iterator iterator;
		typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::Constiterator const_iterator;

		map() = default;

		map(const map<k, T>& key)
			:_root(key._root)
		{ }


		pair<iterator, bool> insert(const pair<k, T>& key)
		{
			return _root.Insert(key);
		}

		iterator begin()
		{
			return _root.begin();
		}


		const_iterator begin()const
		{
			return _root.begin();
		}

		iterator end()
		{
			return _root.end();
		}

		const_iterator end()const
		{
			return _root.end();
		}

		iterator find(const k& key)
		{
			return _root.Find(key);
		}

		bool empty()
		{
			return _root.empty();
		}

	private:

		RBTree<k, pair<const k, T>, MapKeyofT> _root;
	};
}

map中的很多都与set 相似但是map 比set 多重载了operator[ ]

oparetor[ ] 的实现

所以我们可以这么写:
 

		T& operator[](const k& key)
		{
			return (insert({ key, T() }).first)->second;
		}

最后整体代码如下:

	template<class k, class T>
	class map
	{
		struct MapKeyofT
		{
			const k& operator()(const pair<k, T>& key)
			{
				return key.first;
			}
		};


	public:
		typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::iterator iterator;
		typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::Constiterator const_iterator;

		map() = default;

		map(const map<k, T>& key)
			:_root(key._root)
		{ }


		pair<iterator, bool> insert(const pair<k, T>& key)
		{
			return _root.Insert(key);
		}

		iterator begin()
		{
			return _root.begin();
		}


		const_iterator begin()const
		{
			return _root.begin();
		}

		iterator end()
		{
			return _root.end();
		}

		const_iterator end()const
		{
			return _root.end();
		}

		iterator find(const k& key)
		{
			return _root.Find(key);
		}

		bool empty()
		{
			return _root.empty();
		}


		//(*((this->insert(make_pair(k,mapped_type())).first)).second

		T& operator[](const k& key)
		{
			return (insert({ key, T() }).first)->second;
		}
	private:

		RBTree<k, pair<const k, T>, MapKeyofT> _root;
	};

void test_map()
{
	std::map<string, string> dict;
	dict.insert({ "sort", "排序" });
	dict.insert({ "left", "左边" });
	dict.insert({ "right", "右边" });


	//const std::map<string, string> dict = dict1;
	dict["left"];
	dict["insert"];
	dict["string"];

	auto it = dict.begin();
	while (it != dict.end())
	{
		// 不能修改first,可以修改second
		//it->first += 'x';
		it->second += 'x';

		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值