C++之模拟实现map和set

这篇具有很好参考价值的文章主要介绍了C++之模拟实现map和set。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

红黑树源代码

#pragma once

enum color
{
	BLACK,
	RED
};
template<class K, class V>
struct RBTreeNode
{
	//三叉链
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;

	//存储的键值对
	pair<K, V> _kv;

	//结点的颜色
	color _col; //红/黑

	//构造函数
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _col(RED)
	{}
};


template <class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
	{
		//根结点为空
		if (_root == nullptr)
		{
			//创建根结点
			_root = new Node(kv);
			//颜色变为黑
			_root->_col = BLACK;
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;

		while (cur)
		{
			//如果插入key值小于根结点key值
			if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			//如果插入key值大于根结点key值
			else if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			//相等,返回false
			else
			{
				return false;
			}
		}

		//创建cur结点
		cur = new Node(kv);
		//颜色初始化为红色
		cur->_col = RED;

		//如果插入key值小于parent结点key值
		if (parent->_kv.first > kv.first)
		{
			//在左边插入
			parent->_left = cur;
		}
		//如果插入key值大于parent结点key值
		else
		{
			//在右边插入
			parent->_right = cur;
		}
		//跟父结点连接起来
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			//定义祖父节点
			Node* grandfather = parent->_parent;
			assert(grandfather);
			assert(grandfather->_col == BLACK);

			//如果父结点在祖父节点左边
			if (parent == grandfather->_left)
			{
				//定义叔叔结点在祖父结点右边
				Node* uncle = grandfather->_right;
				//情况一:
				//叔叔结点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//进行颜色调整
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;

				}
				//情况二和三:
				//叔叔结点不存在或者存在且为黑
				else
				{
					//插入结点在父结点左边
					if (cur == parent->_left)
					{
						//右单旋+颜色调整
						RotateR(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					//插入结点在父结点左边
					else
					{
						//左右双旋+颜色调整
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;

					}
					break;
				}
			}
			//如果父结点在祖父节点右边
			else
			{
				//定义叔叔结点在祖父结点左边
				Node* uncle = grandfather->_left;
				//情况一:
				//叔叔结点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//颜色调整
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					//向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二和三:
				//叔叔结点不存在或者存在且为黑
				else
				{
					//插入结点在父结点右边
					if (cur == parent->_right)
					{
						//左单旋+颜色调整
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					//插入结点在父结点左边
					else
					{
						//右左双旋+颜色调整
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}
		//根结点变为黑色
		_root->_col = BLACK;
		return true;
	}
private:
	void RotateL(Node* parent)
	{
		//记录parent结点的父结点
		Node* ppNode = parent->_parent;

		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		//建立parent与subRL之间的关系
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		//建立parent与subR之间的关系
		subR->_left = parent;
		parent->_parent = subR;

		//判断根结点是否就是parent
		if (_root == parent)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		Node* ppNode = parent->_parent;

		//建立subLR与parent关系
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		//建立subL与parent关系
		subL->_right = parent;
		parent->_parent = subL;

		//判断根结点是否就是parent
		if (_root == parent)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}
	}
private:
	Node* _root = nullptr;
};

红黑树模板参数控制

我们可以知道,set属于K模型的容器,map属于KV模型的容器,那我们如何使用一棵红黑树来实现map和set呢?

我们就需要控制map和set传入底层红黑树的模板参数,为了与原红黑树的模板参数进行区分,我们将红黑树第二个模板参数的名字改为T。

template <class K, class T>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	//....
private:
	Node* _root = nullptr;

T模板参数可能只是键值Key,也可能是由Key和Value共同构成的键值对。如果是set容器,那么它传入底层红黑树的模板参数就是Key和Key:

namespace gtt
{
	template<class K>
	class set
	{
	public:
		//
	private:
		RBTree<K, K> _t;
	};
}

map它传入底层红黑树的模板参数就是Key以及Key和Value构成的键值对:

namespace gtt
{
	template<class K, class V>
	class map
	{
	public:
		//
	private:
		RBTree<K, pair<K, V>> _t;
	};
}

我们需要注意的是模板中第一个参数K是不可以省略掉的,对于set容器来说第一个参数K和第二个参数K都是一样的,并不会影响什么,对于map容器来说,进行find或者erase时,我们依然需要返回一个key类型的迭代器,所以第一个K不可以省略。

红黑树结点当中存储的数据

对于上层结构:

  1. map:K代表键值Key,T代表由Key和Value构成的键值对。
  2. set容器:K和T都代表键值Key。

对于set容器来说,底层红黑树结点当中存储K和T都是一样的,但是对于map容器来说,底层红黑树就只能存储T了。由于底层红黑树并不知道上层容器到底是map还是set,因此红黑树的结点当中直接存储T就行了,这样一来,当上层容器是set的时候,结点当中存储的是键值Key;当上层容器是map的时候,结点当中存储的就是<Key, Value>键值对。
C++之模拟实现map和set,c++,开发语言
代码如下:

template<class T>
struct RBTreeNode
{
	//三叉链
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	//存储数据
	T _data;

	//结点的颜色
	color _col; //红/黑

	//构造函数
	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		,_data(data)
		, _col(RED)
	{}
};

仿函数的增加

对于set容器,我们需要进行键值比较就是对key值进行比较,也就是直接比较T就可以了,但是对于map容器来说,我们需要比较的是键值对<key,value>中的key,我们需要先将key提取出来,在进行比较。

所以,我们需要在上层map和set中各提供一个仿函数,根据传入的T类型分开进行比较操作:

set仿函数:

namespace gtt
{
	template<class K>
	class set
	{
		//仿函数
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		//
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}

map仿函数:

namespace gtt
{
	template<class K, class V>
	class map
	{
		//仿函数
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		//
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};
}

我们提供了仿函数以后,在进行传参的过程,编译器就会识别我们是需要调用map进行比较还是调用set进行比较,不同的容器调用不同的比较方式:
C++之模拟实现map和set,c++,开发语言

正向迭代器的实现

红黑树的正向迭代器实际上就是对结点指针进行了封装,因此在正向迭代器当中实际上就只有一个成员变量,那就是正向迭代器所封装结点的指针。

template<class T, class Ref, class Ptr>
struct __TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __TreeIterator<T, Ref, Ptr> Self;

	Node* _node;

	//构造函数
	__TreeIterator(Node* node)
		:_node(node)
	{}
};

* 运算符重载

解引用操作,我们直接返回结点数据的引用即可:

//解引用
Ref operator*()
{
	return _node->_data;
}

->运算符重载

->也就是返回结点数据的地址:

//->
Ptr operator->()
{
	return &(_node->_data);
}

!=和==运算符重载

!=和==就是判断两个迭代器所封装的结点是否是同一个

//不等于
bool operator!=(const Self& s) const
{
	return _node != s._node;
}

++运算符重载

红黑树的正向迭代器时,一个结点的正向迭代器进行++操作后,应该根据红黑树中序遍历的序列找到当前结点的下一个结点。

逻辑就是:

  1. 如果当前结点的右子树不为空,则++操作后应该找到其右子树当中的最左结点。
  2. 如果当前结点的右子树为空,则++操作后应该在该结点的祖先结点中,找到孩子不在父亲右的祖先。
    C++之模拟实现map和set,c++,开发语言
    前置++代码如下:
Self& operator++()
{
	//右子树不为空,就去找右子树中最左节点
	if (_node->_right)
	{
		Node* left = _node->_right;

		while (left->_left)
		{
			left = left->_left;
		}
		//++后变为该结点
		_node = left;
	}
	//右子树为空,就去找孩子不在父亲右的祖先
	else
	{
		Node* parent = _node->_parent;
		Node* cur = _node;

		while (parent && cur == parent->_right)
		{
			cur = parent;
			parent = parent->_parent;
		}
		//++后变为该结点
		_node = parent;
	}

	return *this;
}

- -运算符重载

红黑树的正向迭代器时,一个结点的正向迭代器进行–操作后,应该根据红黑树中序遍历的序列找到当前结点的前一个结点:

逻辑如下:

  1. 如果当前结点的左子树不为空,则–操作后应该找到其左子树当中的最右结点。
  2. 如果当前结点的左子树为空,则–操作后应该在该结点的祖先结点中,找到孩子不在父亲左的祖先。

代码如下:文章来源地址https://www.toymoban.com/news/detail-707346.html

Self& operator--()
{
	//左子树不为空,就去找左子树中最右节点
	if (_node->_left)
	{
		Node* right = _node->_left;

		while (right->_right)
		{
			right = right->_right;
		}
		//--后变为该结点
		_node = right;
	}
	//左子树为空,就去找孩子不在父亲左的祖先
	else
	{
		Node* parent = _node->_parent;
		Node* cur = _node;

		while (parent && cur == parent->_left)
		{
			cur = parent;
			parent = parent->_parent;
		}
		//--变为该结点
		_node = parent;
	}
}

begin()与end()实现

  1. begin函数返回中序序列当中第一个结点的正向迭代器,即最左结点。
  2. end函数返回中序序列当中最后一个结点下一个位置的正向迭代器,这里直接用空指针构造一个正向迭代器。
template <class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __TreeIterator<T, T&, T*> iterator;//正向迭代器
	
	iterator begin()
	{
		Node* left = _root;
		
		//寻找最左结点
		while (left && left->_left)
		{
			left = left->_left;
		}

		//返回最左结点的正向迭代器
		return iterator(left);
	}

	iterator end()
	{
		//返回由nullptr构造得到的正向迭代器
		return iterator(nullptr);
	}
private:
	Node* _root = nullptr;

set的模拟实现

namespace gtt
{
	template<class K>
	class set
	{
		//仿函数
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
		//begin()
		iterator begin()
		{
			//调用红黑树的begin()
			return _t.begin();
		}
		//end()
		iterator end()
		{
			//调用红黑树的end()
			return _t.end();
		}
		//插入函数
		pair<iterator, bool> Insert(const K& key)
		{
			//调用红黑树的Insert
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};

map的模拟实现

namespace gtt
{
	template<class K, class V>
	class map
	{
		//仿函数
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
		//begin()
		iterator begin()
		{
			return _t.begin();
		}
		//end()
		iterator end()
		{
			return _t.end();
		}
		//插入函数
		pair<iterator, bool> Insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}
		//[]运算符重载
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = Insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};

封装后红黑树代码

#pragma once

enum color
{
	BLACK,
	RED
};
template<class T>
struct RBTreeNode
{
	//三叉链
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	//存储数据
	T _data;

	//结点的颜色
	color _col; //红/黑

	//构造函数
	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		,_data(data)
		, _col(RED)
	{}
};

template<class T, class Ref, class Ptr>
struct __TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __TreeIterator<T, Ref, Ptr> Self;

	Node* _node;

	//构造函数
	__TreeIterator(Node* node)
		:_node(node)
	{}

	//解引用
	Ref operator*()
	{
		return _node->_data;
	}

	//->
	Ptr operator->()
	{
		return &(_node->_data);
	}

	//不等于
	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}

	//等于
	bool operator==(const Self& s) const
	{
		return _node == s._node;
	}

	Self& operator++()
	{
		//右子树不为空,就去找右子树中最左节点
		if (_node->_right)
		{
			Node* left = _node->_right;

			while (left->_left)
			{
				left = left->_left;
			}
			//++后变为该结点
			_node = left;
		}
		//右子树为空,就去找孩子不在父亲右的祖先
		else
		{
			Node* parent = _node->_parent;
			Node* cur = _node;

			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}
			//++后变为该结点
			_node = parent;
		}

		return *this;
	}

	Self& operator--()
	{
		//左子树不为空,就去找左子树中最右节点
		if (_node->_left)
		{
			Node* right = _node->_left;

			while (right->_right)
			{
				right = right->_right;
			}
			//--后变为该结点
			_node = right;
		}
		//左子树为空,就去找孩子不在父亲左的祖先
		else
		{
			Node* parent = _node->_parent;
			Node* cur = _node;

			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}
			//--变为该结点
			_node = parent;
		}
	}
};

template <class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __TreeIterator<T, T&, T*> iterator;//正向迭代器
	iterator begin()
	{
		Node* left = _root;
		
		//寻找最左结点
		while (left && left->_left)
		{
			left = left->_left;
		}

		//返回最左结点的正向迭代器
		return iterator(left);
	}

	iterator end()
	{
		//返回由nullptr构造得到的正向迭代器
		return iterator(nullptr);
	}
	pair<iterator, bool> Insert(const T& data)
	{
		KeyOfT kot;
		//根结点为空
		if (_root == nullptr)
		{
			//创建根结点
			_root = new Node(data);
			//颜色变为黑
			_root->_col = BLACK;
			return make_pair(iterator(_root), true);
		}

		Node* cur = _root;
		Node* parent = nullptr;

		while (cur)
		{
			//如果插入key值小于根结点key值
			if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			//如果插入key值大于根结点key值
			else if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			//相等,返回false
			else
			{
				return make_pair(iterator(cur), false);
			}
		}

		//创建cur结点
		cur = new Node(data);
		Node* newnode = cur;
		//颜色初始化为红色
		cur->_col = RED;

		//如果插入key值小于parent结点key值
		if (kot(parent->_data) > kot(data))
		{
			//在左边插入
			parent->_left = cur;
		}
		//如果插入key值大于parent结点key值
		else
		{
			//在右边插入
			parent->_right = cur;
		}
		//跟父结点连接起来
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			//定义祖父节点
			Node* grandfather = parent->_parent;
			assert(grandfather);
			assert(grandfather->_col == BLACK);

			//如果父结点在祖父节点左边
			if (parent == grandfather->_left)
			{
				//定义叔叔结点在祖父结点右边
				Node* uncle = grandfather->_right;
				//情况一:
				//叔叔结点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//进行颜色调整
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二和三:
				//叔叔结点不存在或者存在且为黑
				else
				{
					//插入结点在父结点左边
					if (cur == parent->_left)
					{
						//右单旋+颜色调整
						RotateR(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					//插入结点在父结点左边
					else
					{
						//左右双旋+颜色调整
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;

					}
					break;
				}
			}
			//如果父结点在祖父节点右边
			else
			{
				//定义叔叔结点在祖父结点左边
				Node* uncle = grandfather->_left;
				//情况一:
				//叔叔结点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//颜色调整
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					//向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二和三:
				//叔叔结点不存在或者存在且为黑
				else
				{
					//插入结点在父结点右边
					if (cur == parent->_right)
					{
						//左单旋+颜色调整
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					//插入结点在父结点左边
					else
					{
						//右左双旋+颜色调整
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}
		//根结点变为黑色
		_root->_col = BLACK;
		return make_pair(iterator(newnode), true);
	}
	void RotateL(Node* parent)
	{
		//记录parent结点的父结点
		Node* ppNode = parent->_parent;

		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		//建立parent与subRL之间的关系
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		//建立parent与subR之间的关系
		subR->_left = parent;
		parent->_parent = subR;

		//判断根结点是否就是parent
		if (_root == parent)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		Node* ppNode = parent->_parent;

		//建立subLR与parent关系
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		//建立subL与parent关系
		subL->_right = parent;
		parent->_parent = subL;

		//判断根结点是否就是parent
		if (_root == parent)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}
	}
private:
	Node* _root = nullptr;
};


到了这里,关于C++之模拟实现map和set的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】 使用红黑树模拟实现STL中的map与set

    前面的文章我们学习了红黑树,也提到了C++STL中的map和set的底层其实就是用的红黑树来实现的(而map和set的使用我们前面也学过了)。 既然红黑树我们也学习过了,那这篇文章我们就用红黑树来简单实现一下STL中的map和set,重点是学习它的框架。 上一篇文章我们实现了红黑

    2024年02月12日
    浏览(31)
  • 【C++练级之路】【Lv.17】【STL】set类和map类的模拟实现

    快乐的流畅:个人主页 个人专栏:《C语言》《数据结构世界》《进击的C++》 远方有一堆篝火,在为久候之人燃烧! STL库中的set类和map类,其底层原理都是 通过红黑树来实现 的。尽管set和map可以各自实现一棵红黑树,但是为了提高代码的复用率,STL库中将红黑树进行了一定

    2024年04月16日
    浏览(38)
  • 【C++】用哈希桶模拟实现unordered_set和unordered_map

    顺序结构中(数组)查找一个元素需要遍历整个数组,时间复杂度为O(N);树形结构中(二叉搜索树)查找一个元素,时间复杂度最多为树的高度次logN。理想的搜索方法: 可以不经过任何比较,一次直接从表中得到要搜索的元素。 构造一种存储结构, 通过某种函数使元素的

    2024年04月11日
    浏览(51)
  • 由[哈希/散列]模拟实现[unordered_map/unordered_set] (手撕迭代器)

    以下两篇文章均为笔者的呕心沥血 想要搞懂本篇文章的uu请自行查阅 哈希/散列的细节实现 哈希/散列–哈希表[思想到结构][==修订版==] 手撕迭代器的细节处理 模拟实现map/set[改编红黑树实现map/set容器底层]

    2024年02月07日
    浏览(45)
  • 【C++】set和map的底层AVL树的实现

    AVL树 文章目录 前言 一、AVL树的实现 总结 上一篇文章对 map/multimap/set/multiset 进行了简单的介绍,在其文档介绍中发现,这几个容器有个共同点是: 其底层都是按照二叉搜索树来实现的 ,但是二叉搜索树有其自身的缺陷,假如往树中 插入的元素有序或者接近有序,二叉搜索

    2024年02月06日
    浏览(40)
  • [C++]哈希表实现,unordered_map\set封装

    目录 ​​​​​​​ 前言: 1 哈希 1.1 为什么有哈希 1.2 哈希结构 1.3 哈希冲突  2 闭散列 2.1 闭散列结点结构和位置状态表示 2.2 哈希类结构 2.3 插入 2.4 查找 2.5 删除 3 开散列 3.1 哈希表结点结构 3.2 哈希表结构 3.3 插入 3.4 查找、删除 3.5 迭代器实现 4 map和set的封装 4.1 map的封

    2024年02月08日
    浏览(49)
  • 【C++】哈希表封装实现 unordered_map 和 unordered_set

    在 C++98 中,STL 提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 O(logN),即最差情况下只需要比较红黑树的高度次;但是当树中的节点非常多时,其查询效率也不够极致。 最好的查询是,不进行比较或只进行常数次比较就能够将元素找到,因此在 C++11 中,

    2023年04月16日
    浏览(49)
  • C++【unordered_map/set的底层实现-哈希表】—含有源代码

    前面讲了STL中的map和set容器以及封装实现,虽然它们的查找效率是O(logN),但是当红黑树中的节点非常多时,因为红黑树不是严格平衡,树的高度可能变得很大,就是一变高一边低的情况,这会导致查询操作的时间复杂度变为O(N),所以后面就出现了四个unordered系列的关联式容

    2024年02月08日
    浏览(45)
  • 【C++】开散列哈希表封装实现unordered_map和unordered_set

    在未达成目的之前,一切具有诱惑力的事物都显得那么不堪一击 1. 在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N l o g 2 ​ N ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。 最好的查询是

    2023年04月09日
    浏览(84)
  • C++进阶--使用哈希表实现unordered_map和unordered_set的原理与实例

    本文将介绍如何使用哈希表来实现C++ STL库中的unordered_map和unordered_set容器。我们将会解释哈希表的基本原理,并给出具体的代码示例,帮助读者更好地理解和应用哈希表。 哈希原理讲解–链接入口 set和map的实现的文章,与unordered_map实现类似 unordered_set是一种集合存储的容器

    2024年04月09日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包