模拟实现map&set

模拟实现map&set

1. 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通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))

2. map的模板参数说明

在这里插入图片描述

  • key: 键值对中key的类型
  • T: 键值对中value的类型
  • Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
  • Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器

注意:在使用map时,需要包含头文件

3. map的构造

函数声明 功能介绍
map() 构造一个空的map

4. map的迭代器

在这里插入图片描述

5. map的容量与元素访问

函数声明 功能简介
bool empty ( ) const 检测map中的元素是否为空,是返回true,否则返回false
size_type size() const 返回map中有效元素的个数
mapped_type& operator[] (constkey_type& k) 返回去key对应的value

注意当key不存在时,mapped_type& operator[] (constkey_type& k)相当于用默认value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常

6. map中元素的修改

函数声明 功能简介
pair<iterator,bool> insert (const value_type& x ) 在map中插入键值对x,注意x是一个键值对,返回值也是键值对:iterator代表新插入元素的位置,bool代表释放插入成功
void erase ( iterator position ) 删除position位置上的元素
size_type erase ( const key_type& x) 删除键值为x的元素
void erase ( iterator first,iterator last ) 删除[first, last)区间中的元素
void swap (map<Key,T,Compare,Allocator>&mp) 交换两个map中的元素
void clear ( ) 将map中的元素清空
iterator find ( const key_type& x) 在map中插入key为x的元素,找到返回该元素的位置的迭代器,否则返回end
const_iterator find ( const key_type& x ) const 在map中插入key为x的元素,找到返回该元素的位置的const迭代器,否则返回cend
size_type count ( const key_type& x ) const 返回key为x的键值在map中的个数,注意map中key是唯一的,因此该函数的返回值要么为0,要么为1,因此也可以用该函数来检测一个key是否在map中

【总结】

  1. map中的的元素是键值对
  2. map中的key是唯一的,并且不能修改
  3. 默认按照小于的方式对key进行比较
  4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
  5. map的底层为平衡搜索树(红黑树),查找效率比较高
  6. 支持[]操作符,operator[]中实际进行插入查找。

set/multimap/multiset的接口和map基本类似,主要的区别在于元素能否重复,是否可以使用operator[]操作

7. map的模拟实现

map的底层使用的是红黑树,所以先封装一个红黑树
红黑树

要实现map还需要在前文的基础上进行填充一些操作:

1. 红黑树的迭代器

迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代器,需要考虑以前问题:

begin()与end()

  • STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一 个有序的序列,
  • 因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位置,end()放在最大节点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪块?
  • 能否给成nullptr呢?答案是行不通的,因为对end()位置的迭代器进行–操作,必须要能找最后一个元素,此处就不行,因此最好的方式是将end()放在头结点的位置

2. operator++()与operator–()

// 找迭代器的下一个节点,下一个节点肯定比其大
void Increasement()
{
	//分两种情况讨论:_pNode的右子树存在和不存在
	// 右子树存在
	if(_pNode->_pRight)
	{
		// 右子树中最小的节点,即右子树中最左侧节点
		_pNode = _pNode->_pRight;
		while(_pNode->_pLeft)
			_pNode = _pNode->_pLeft;
	}
	else
	{
		// 右子树不存在,向上查找,直到_pNode != pParent->right
		PNode pParent = _pNode->_pParent;
		while(pParent->_pRight == _pNode)
		{
			_pNode = pParent;
			pParent = _pNode->_pParent;
		}
		// 特殊情况:根节点没有右子树
		if(_pNode->_pRight != pParent)
			_pNode = pParent;
	}
}

// 获取迭代器指向节点的前一个节点
void Decreasement()
{
		//分三种情况讨论:_pNode 在head的位置,_pNode 左子树存在,_pNode 左子树不存在
		// 1. _pNode 在head的位置,--应该将_pNode放在红黑树中最大节点的位置
	if(_pNode->_pParent->_pParent == _pNode && _pNode->_color == RED)
	_pNode = _pNode->_pRight;
	else if(_pNode->_pLeft)
	{
		// 2. _pNode的左子树存在,在左子树中找最大的节点,即左子树中最右侧节点
		_pNode = _pNode->_pLeft;
		while(_pNode->_pRight)
			_pNode = _pNode->_pRight;
	}
	else
	{
		// _pNode的左子树不存在,只能向上找
		PNode pParent = _pNode->_pParent;
		while(_pNode == pParent->_pLeft)
		{
			_pNode = pParent;
			pParent = _pNode->_pParent;
		}
		_pNode = pParent;
	}
}

3. 2 改造红黑树

// 因为关联式容器中存储的是<key, value>的键值对,因此
// k为key的类型,
// ValueType: 如果是map,则为pair<K, V>; 如果是set,则为k
// KeyOfValue: 通过value来获取key的一个仿函数类
template<class K, class ValueType, class KeyOfValue>
	class RBTree
	{
		typedef RBTreeNode<ValueType> Node;
		typedef Node* PNode;
	public:
		typedef RBTreeIterator<ValueType, ValueType*, ValueType&> 		Iterator;
	public:
		RBTree();
		~RBTree()
/////////////////////////////////////////////////////////////////////
// Iterator
		Iterator Begin(){ return Iterator(_pHead->_pLeft);}
		Iterator End(){ return Iterator(_pHead);}
//////////////////////////////////////////////////////////////////
// Modify
		pair<Iterator, bool> Insert(const ValueType& data)
		{
			// 插入节点并进行调整
			// 参考上文...
			return make_pair(Iterator(pNewNode), true);
		}
		// 将红黑树中的节点清空
		void Clear();
		Iterator Find(const K& key);
//////////////////////////////////////////////////////////////////
// capacity
		size_t Size()const;
		bool Empty()const;
		// ……
	private:
		PNode _pHead;
		size_t _size; // 红黑树中有效节点的个数
};

RBTree.hpp

#pragma once
#include<algorithm>

enum Color {
	RED,
	BLACK
};

template<class ValueType>
struct RBTreeNode
{
	RBTreeNode(const ValueType& data = ValueType(), Color color = RED)
		:_pLeft(nullptr)
		,_pRight(nullptr)
		,_pParent(nullptr)
		,_data(data)
		,_color(color)
	{}

	RBTreeNode<ValueType>* _pLeft;
	RBTreeNode<ValueType>* _pRight;
	RBTreeNode<ValueType>* _pParent;
	ValueType _data;
	Color _color;
};

template<class T>
class Iterator {
public:
	typedef RBTreeNode<T> Node;
	typedef Iterator<T> Self;

	Iterator(Node* pNode=nullptr)
		:_pNode(pNode)
	{}
	T& operator*() {
		return _pNode->_data;
	}
	T* operator->() {
		return &(_pNode->_data);
	}
	Self& operator++() {
		Next();
		return *this;
	}
	Self operator++(int) {
		Self tmp(_pNode);
		Next();
		return tmp;
	}
	bool operator==(Self& t){
		return _pNode == t._pNode;
	}
	bool operator!=(Self& t){
		return _pNode != t._pNode;
	}
	Self& operator--() {
		Prev();
		return *this;
	}
	Self operator--(int) {
		Self tmp(_pNode);
		Prev();
		return tmp;
	}
private:
	void Next() {
		//如果有右子树
		if (_pNode->_pRight) {
			_pNode = _pNode->_pRight;
			while (_pNode->_pLeft)
				_pNode = _pNode->_pLeft;
			return;
		}
		Node* pParent = _pNode->_pParent;
		while (pParent->_pRight == _pNode) {
			_pNode = pParent;
			pParent = _pNode->_pParent;
		}
		//根节点没有右子树,并且迭代器刚好在根节点位置
		if (_pNode->_pRight != pParent)
			_pNode = pParent;
	}
	void Prev() {
		//1._pNode在head位置(即end()位置),应该将_pNode放在最大结点处
		if (_pNode->_pParent->_pParent == _pNode && _pNode->_color == RED)
			_pNode = _pNode->_pRight;
		//2. 如果有左子树
		else if (_pNode->_pLeft) {
			_pNode = _pNode->_pLeft;
			while (_pNode->_pRight)
				_pNode = _pNode->_pRight;
		}
		else {
			Node* pParent = _pNode->_pParent;
			while (pParent->_pLeft == _pNode) {
				_pNode = pParent;
				pParent = _pNode->_pParent;
			}
			_pNode = pParent;
		}
	}
	Node* _pNode;
};

template<class T,class KorV>
class RBTree {
public:
	typedef RBTreeNode<T> Node;
	typedef Node* PNode;
	typedef RBTree<T, KorV> Self;
	typedef Iterator<T> iterator;
public:
	RBTree()
		:_pHead(new Node)
		,_size(0)
	{
		_pHead->_pLeft = _pHead;
		_pHead->_pRight = _pHead;
	}
	~RBTree() {
		if (_pHead->_pParent)
			del(_pHead->_pParent);
		delete _pHead;
	}
	std::pair<iterator,bool> Insert(const T& data) {
		PNode& pRoot = GetRoot();   //获取根节点
		PNode newPtr = nullptr;
		if (nullptr == pRoot) {   //如果红黑树为空
			newPtr = pRoot = new Node(data, BLACK);
			pRoot->_pParent = _pHead;
		}
		else {
			PNode pParent = nullptr;
			PNode pCur = pRoot;
			//插入节点
			while (pCur) {
				pParent = pCur;
				if (KorV()(data) < KorV()(pCur->_data))
					pCur = pCur->_pLeft;
				else if (KorV()(data) > KorV()(pCur->_data))
					pCur = pCur->_pRight;
				else
					return std::make_pair(iterator(), false);
			}
			newPtr = pCur = new Node(data);
			if (KorV()(data) < KorV()(pParent->_data)) {
				pParent->_pLeft = pCur;
				pCur->_pParent = pParent;
			}
			else {
				pParent->_pRight = pCur;
				pCur->_pParent = pParent;
			}

			//检测新节点插入后。红黑树的性质是否遭到破坏
			while (pParent != _pHead && RED == pParent->_color) {
				PNode pGrand = pParent->_pParent;
				//pParent在pGrand左侧的情况
				if (pParent == pGrand->_pLeft) {
					PNode unclue = pGrand->_pRight;
					//情况一
					if (unclue&&RED == unclue->_color) {
						pParent->_color = BLACK;
						unclue->_color = BLACK;
						pGrand->_color = RED;

						pCur = pGrand;
						pParent = pCur->_pParent;
					}
					else {
						//情况三
						if (pParent->_pRight == pCur) {
							RotateLeft(pParent);
							std::swap(pParent, pCur);
						}
						//情况二
						RotateRight(pGrand);
						pParent->_color = BLACK;
						pGrand->_color = RED;
					}
				}
				//pParent在pGrand右侧的情况
				else {
					PNode unclue = pGrand->_pLeft;
					//情况一
					if (unclue&&RED == unclue->_color) {
						pParent->_color = BLACK;
						unclue->_color = BLACK;
						pGrand->_color = RED;

						pCur = pGrand;
						pParent = pCur->_pParent;
					}
					else {
						//情况三
						if (pParent->_pLeft == pCur) {
							RotateRight(pParent);
							std::swap(pParent, pCur);
						}
						//情况二
						RotateLeft(pGrand);
						pParent->_color = BLACK;
						pGrand->_color = RED;
					}
				}
			}
		}
		//根节点的颜色可能被修改,将其改回黑色
		pRoot->_color = BLACK;
		//更新头结点的左右孩子
		_pHead->_pLeft = LeftMost();
		_pHead->_pRight = RightMost();
		++_size;
		return std::make_pair(iterator(newPtr), true);
	}
	void Inorder()
	{
		_InOrder(GetRoot());
		std::cout << std::endl;
	}

	bool IsValidRBTree()
	{
		PNode pRoot = GetRoot();
		// 空树也是红黑树
		if (nullptr == pRoot)
			return true;
		// 检测根节点是否满足情况
		if (BLACK != pRoot->_color)
		{
			std::cout << "违反红黑树性质二:根节点必须为黑色" << std::endl;
			return false;
		}
		// 获取任意一条路径中黑色节点的个数
		size_t blackCount = 0;
		PNode pCur = pRoot;
		while (pCur)
		{
			if (BLACK == pCur->_color)
				blackCount++;
			pCur = pCur->_pLeft;
		}
		// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
		size_t k = 0;
		return _IsValidRBTree(pRoot, k, blackCount);
	}

	iterator find(const T& data)const {
		PNode ptr = GetRoot();
		while (ptr) {
			if (KorV()(data) == KorV()(ptr->_data))
				return iterator(ptr);
			else if (KorV()(data) < KorV()(ptr->_data))
				ptr = ptr->_pLeft;
			else
				ptr = ptr->_pRight;
		}
		return end();
	}

	size_t size()const {
		return _size;
	}

	bool empty()const {
		return _size == 0;
	}

	iterator begin() {
		return iterator(_pHead->_pLeft);
	}
	iterator end() {
		return iterator(_pHead);
	}
private:
	void _InOrder(Node* pRoot)
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			std::cout << pRoot->_data << " ";
			_InOrder(pRoot->_pRight);
		}
	}
	void del(PNode ptr) {
		if (ptr->_pLeft)
			del(ptr->_pLeft);
		if (ptr->_pRight)
			del(ptr->_pRight);
		delete ptr;
	}
	bool _IsValidRBTree(PNode pRoot, size_t k, const size_t blackCount) {
		//走到null之后,判断k和black是否相等
		if (nullptr == pRoot)
		{
			if (k != blackCount)
			{
				std::cout << "违反性质四:每条路径中黑色节点的个数必须相同" << std::endl;
				return false;
			}
			return true;
		}
		// 统计黑色节点的个数
		if (BLACK == pRoot->_color)
			k++;
		// 检测当前节点与其双亲是否都为红色
		PNode pParent = pRoot->_pParent;
		if (pParent && RED == pParent->_color && RED == pRoot->_color)
		{
			std::cout << "违反性质三:没有连在一起的红色节点" << std::endl;
			return false;
		}
		return _IsValidRBTree(pRoot->_pLeft, k, blackCount) &&
			_IsValidRBTree(pRoot->_pRight, k, blackCount);
	}
	PNode& GetRoot() {
		return _pHead->_pParent;
	}
	PNode LeftMost() {
		PNode ptr = GetRoot();
		if (!ptr)
			return _pHead;
		while (ptr->_pLeft)
			ptr = ptr->_pLeft;
		return ptr;
	}
	PNode RightMost() {
		PNode ptr = GetRoot();
		if (!ptr)
			return _pHead;
		while (ptr->_pRight)
			ptr = ptr->_pRight;
		return ptr;
	}
	void RotateLeft(PNode pParent) {
		PNode pPParent = pParent->_pParent;
		PNode pRight = pParent->_pRight;
		pParent->_pRight = pRight->_pLeft;
		if (pRight->_pLeft)
			pRight->_pLeft->_pParent = pParent;
		pRight->_pLeft = pParent;
		pParent->_pParent = pRight;
		//当pPParent不存在时
		if (pPParent==_pHead) {
			//设置pRight为根节点
			_pHead->_pParent = pRight;
			pRight->_pParent = _pHead;
		}
		else {
			if (pPParent->_pLeft == pParent) {
				pPParent->_pLeft = pRight;
				pRight->_pParent = pPParent;
			}
			else {
				pPParent->_pRight = pRight;
				pRight->_pParent = pPParent;
			}
		}
	}
	void RotateRight(PNode pParent) {
		PNode pPParent = pParent->_pParent;
		PNode pLeft = pParent->_pLeft;
		pParent->_pLeft = pLeft->_pRight;
		if (pLeft->_pRight)
			pLeft->_pRight->_pParent = pParent;
		pLeft->_pRight = pParent;
		pParent->_pParent = pLeft;
		//当pPParent不存在时
		if (pPParent == _pHead) {
			//设置pLeft为根节点
			_pHead->_pParent = pLeft;
			pLeft->_pParent = _pHead;
		}
		else {
			if (pPParent->_pLeft == pParent) {
				pPParent->_pLeft = pLeft;
				pLeft->_pParent = pPParent;
			}
			else {
				pPParent->_pRight = pLeft;
				pLeft->_pParent = pPParent;
			}
		}
	}
private:
	PNode _pHead;    //头结点(根节点的父亲节点)
	size_t _size;
};

map.hpp

#include"RBTree.hpp"

template<class K,class V>
class Map {
	typedef std::pair<K, V> ValueType;
	struct KorV {
		const K& operator()(const ValueType& v)const{
			return v.first;
		}
	};
	typename typedef RBTree<ValueType, KorV>::iterator iterator;
public:
	Map() 
	{}
	iterator begin() {
		return _tree.begin();
	}
	iterator end() {
		return _tree.end();
	}
	size_t size()const {
		return _tree.size();
	}
	bool empty()const {
		return _tree.empty();
	}
	std::pair<iterator, bool> insert(const ValueType& data) {
		return _tree.Insert(data);
	}
	iterator find(const K& key)const{
		return _tree.find(ValueType(key, V()));
	}
	V& operator[](const K& k) {
		return (*(insert(ValueType(k, V())).first)).second;
	}
private:
	RBTree<ValueType, KorV> _tree;
};

8. set的模拟实现

set.hpp

#include"RBTree.hpp"

template<class K>
class Set {
	typedef K ValueType;
	struct KorV {
		const K& operator()(const ValueType& data) {
			return data;
		}
	};
public:
	typename typedef RBTree<ValueType, KorV>::iterator iterator;
public:
	Set()
	{}
	iterator begin() {
		return _tree.begin();
	}
	iterator end() {
		return _tree.end();
	}
	std::pair<iterator, bool> insert(const ValueType& data) {
		return _tree.Insert(data);
	}
	size_t size()const {
		return _tree.size();
	}
	bool empty()const {
		return _tree.empty();
	}
	iterator find(const K& key) {
		return _tree.find(key);
	}
private:
	RBTree<ValueType, KorV> _tree;
};

发布了150 篇原创文章 · 获赞 89 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/wolfGuiDao/article/details/105177542