STL —— map、set模拟实现

目录

1.map和set的应用

2.红黑树的封装(部分功能)

3.map的封装(部分功能)

4.set的封装(部分功能)

5.完成代码

1.map和set的应用

map和set的使用通过查找相关文档即可熟悉。这里给出几道习题用于熟悉map和set的用法:

692. 前K个高频单词        使用map解题

KY264 单词识别        使用map解题

160. 相交链表        使用set解题

138. 复制带随机指针的链表        使用map解题

class Solution {
public:
    Node* copyRandomList(Node* head) {
        map<Node*,Node*> m;//map映射旧节点和新节点
        Node* cur = head;
        while(cur)
        {
            m[cur] = new Node(cur->val);//新节点使用旧节点的val值创建
            cur = cur->next;
        }

        cur = head;
        while(cur)
        {
            m[cur]->next = m[cur->next];//新节点的next指针是旧节点对应的v模型
            m[cur]->random = m[cur->random];//新节点的random指针是旧节点对应的v模型
            cur = cur->next;
        }
        return m[head];
    }
};

2.红黑树的封装(部分功能)

namespace ly
{
	enum Corlor	//枚举颜色
	{
		RED, BLACK
	};

	template <class KV>	//红黑树的节点并不知道KV到底是什么
	struct RBTreeNode
	{
		RBTreeNode<KV>* _left;
		RBTreeNode<KV>* _right;
		RBTreeNode<KV>* _parent;
		KV _data;
		Corlor _cor;

		RBTreeNode(const KV& data)
			:_left(nullptr), _right(nullptr), _parent(nullptr),
			_data(data), _cor(RED)
		{}
	};

	template<class KV,class Ref,class Ptr>//迭代器是指向某一节点的,所以其模板参数为KV
	struct RBTreeIterator//也就说迭代器也不知道指向的KV是什么
	{
		typedef RBTreeNode<KV> Node;
		typedef RBTreeIterator<KV, Ref, Ptr> Self;
		Node* _node;

		RBTreeIterator(Node* node)
			:_node(node)
		{}

		Ref operator*()//解引用就是返回一个KV的引用。至于怎么用,由调用的用户决定
		{
			return _node->_data;
		}

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

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

		// 如何实现迭代器++?
		Self& operator++()
		{
			if (_node->_right)//情况1,如果当前节点的右子树不为空
			{
				//很明显,下一个节点将是右子树中最左节点
				Node* min = _node->_right;
				while (min && min->_left)
				{
					min = min->_left;
				}
				_node = min;
			}
			else//情况2,当前节点的右子树为空
			{
				//那么迭代器就要往上找
				//中序遍历的顺序为 左 根 右
				//也就是说,如果当前节点是其父节点的左孩子
				//那么下一个位置其父节点
				//如果当前节点是其父节点的右孩子
				//说明中序遍历已经走完了,需要重复遍历

				Node* cur = _node;
				Node* parent = cur->_parent;
				while (parent && parent->_right == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
		}
	};

	//使用三个参数兼容set和map使用一份红黑树
	//第一个参数可用作查找
	//第二个参数才是红黑树真正放的节点(要不为K,要不为KV)
	//第三个参数是从KV提取K的仿函数
	template <class K, class KV, class KOfKV>
	class RBTree
	{
	public:
		typedef RBTreeNode<KV> Node;
		typedef RBTreeIterator<KV, KV&, KV*> iterator;//普通迭代器
		typedef RBTreeIterator<KV, const KV&, const KV*> const_iterator;//const迭代器
		   
		iterator begin()
		{
			//最左节点便是第一个节点
			//也就是begin指向的节点
			Node* cur = _root;
			while (cur && cur->_left)
			{
				cur = cur->_left;
			}
			return iterator(cur);
		}
		iterator end()
		{
			//以空作为end迭代器
			return iterator(nullptr);
		}

		const_iterator begin() const
		{
			Node* cur = _root;
			while (cur && cur->_left)
			{
				cur = cur->_left;
			}
			return const_iterator(cur);
		}
		const_iterator end() const
		{
			return const_iterator(nullptr);
		}


		//insert返回键值对
		//注意,这里返回的迭代器都是普通迭代器
		pair<iterator,bool> insert(const KV& data)
		{
			KOfKV kof;//仿函数对象,负责提取KV中的K
			if (_root == nullptr)
			{
				_root = new Node(data);
				_root->_cor = BLACK;	//根节点的颜色必须是黑色
				return make_pair(_root, true);//插入成功second设为true
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (kof(data) < kof(cur->_data))
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (kof(data) > kof(cur->_data))
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					return make_pair(cur,false);//存在则设为false
				}
			}

			cur = new Node(data);
			Node* ret = cur;//因为等会cur的位置会变,这里先记录一下
			cur->_cor = RED;	//新插入的节点颜色为红色
			if (kof(data) < kof(parent->_data))
			{
				parent->_left = cur;
				cur->_parent = parent;
			}
			else if (kof(data) > kof(parent->_data))
			{
				parent->_right = cur;
				cur->_parent = parent;
			}

			// 此时如果新插入的节点破坏了红黑树的性质,就必须做一些微调
			while (parent && parent->_cor == RED)
			{
				// 调整动作
				Node* grandfather = parent->_parent;
				if (grandfather->_left == parent)
				{
					Node* uncle = grandfather->_right;
					if (uncle && uncle->_cor == RED)
					{
						// 情况1

						parent->_cor = uncle->_cor = BLACK;
						grandfather->_cor = RED;

						cur = grandfather;
						parent = cur->_parent;
					}
					else	// unle不存在或uncle存在且为黑
					{
						if (parent->_left == cur)
						{
							// 情况2
							RotateR(grandfather);
							parent->_cor = BLACK;
							grandfather->_cor = RED;
						}
						else if (parent->_right == cur)
						{
							// 情况3
							RotateL(parent);
							RotateR(grandfather);
							cur->_cor = BLACK;
							grandfather->_cor = RED;
						}

						break;	//关键
					}
				}
				else if (grandfather->_right == parent)	//镜像即可
				{
					Node* uncle = grandfather->_left;
					if (uncle && uncle->_cor == RED)
					{
						parent->_cor = uncle->_cor = BLACK;
						grandfather->_cor = RED;

						cur = grandfather;
						parent = cur->_parent;
					}
					else
					{
						if (parent->_right == cur)
						{
							// 情况2
							RotateL(grandfather);
							parent->_cor = BLACK;
							grandfather->_cor = RED;
						}
						else if (parent->_left == cur)
						{
							// 情况3
							RotateR(parent);
							RotateL(grandfather);
							cur->_cor = BLACK;
							grandfather->_cor = RED;
						}
						break;	//关键
					}
				}
			}

			_root->_cor = BLACK;	//确保根节点颜色为黑色
			return make_pair(ret,true);
		}
	private:
		Node* _root = nullptr;


		void RotateL(Node* parent)
		{
			Node* cur = parent->_right;
			Node* curL = cur->_left;	//cur的左树

			parent->_right = curL;	//cur的左树变成parent的右树
			if (curL)
			{
				curL->_parent = parent;
			}

			Node* oldParent = parent->_parent;	//记录parent的父节点
			parent->_parent = cur;	//cur作为parent的父节点
			cur->_left = parent;	//parent作为cur的左树

			if (oldParent == nullptr)
			{
				_root = cur;	//直接让cur作为根节点(因为parent的旧父节点为空)
				cur->_parent = nullptr;
			}
			else
			{
				if (oldParent->_left == parent)
				{
					oldParent->_left = cur;
					cur->_parent = oldParent;
				}
				else if (oldParent->_right == parent)
				{
					oldParent->_right = cur;
					cur->_parent = oldParent;
				}
			}
		}

		void RotateR(Node* parent)
		{
			Node* cur = parent->_left;
			Node* curR = cur->_right;


			parent->_left = curR;	//cur的右树作为parent的左树
			if (curR)
			{
				curR->_parent = parent;
			}

			Node* oldParent = parent->_parent;
			parent->_parent = cur;
			cur->_right = parent;	//parent作为cur的右树

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

解析:迭代器的++算法。这里也有一道对应力扣的题:面试题 04.06. 后继者

3.map的封装(部分功能)

#include "RBTree.h"
namespace ly
{
	template<class K, class V>
	class map
	{
	public:
		struct KeyOfMap//提供给红黑树的仿函数
		{
			K operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};

		//加上typename表示是某类中的类型而非静态变量
		typedef typename RBTree<K, pair<const K, V>, KeyOfMap>::iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, KeyOfMap>::const_iterator const_iterator;

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

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

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

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

		pair<iterator, bool> insert(const pair<const K, V>& kv)
		{
			return _rb.insert(kv);
		}

		V& operator[](const K& k)
		{
			//只通过insert接口实现[]运算符重载
			//1.先使用临时变量接收insert的返回值
			pair<iterator, bool> p = insert(make_pair(k, V()));
			//2.p中的first就是迭代器,指向了insert的节点
			return p.first->second;
		}

	private:
		RBTree<K, pair<const K, V>, KeyOfMap> _rb;//红黑树对象
	};
}

4.set的封装(部分功能)

#include "RBTree.h"
namespace ly
{
	template<class K>
	class set
	{
	public:
		struct KeyOfSet//提供给红黑树的仿函数
		{
			K operator()(const K& k)
			{
				return k;
			}
		};

		//加上typename表示是某类中的类型而非静态变量
		//需要注意,通常我们不希望改变set中K值
		//所以set使用的迭代器都是const迭代器
		typedef typename RBTree<K, K, KeyOfSet>::const_iterator iterator;
		typedef typename RBTree<K, K, KeyOfSet>::const_iterator const_iterator;

		iterator begin() const
		{
			return _rb.begin();
		}

		iterator end() const
		{
			return _rb.end();
		}

		pair<iterator, bool> insert(const K& k)
		{
			/*又因为set使用的const迭代器
			而底层红黑树的insert接口返回的是普通迭代器
			而普通迭代器是不能类型转换成const迭代器的*/
			//return _rb.insert(k);

			//所以需要在底层的迭代器上做更改
			//使得普通迭代器能够构造出const迭代器
			//所以,第一步:先使用普通迭代器的pair对象接收返回值
			pair<typename RBTree<K, K, KeyOfSet>::const_iterator, bool> p = _rb.insert(k);
			//第二步:再用普通迭代器构造出const迭代器
			return pair<iterator, bool>(p.first, p.second);
		}


	private:
		RBTree<K, K, KeyOfSet> _rb;//红黑树对象
	};
}

修改后的迭代器模块:

template<class KV,class Ref,class Ptr>//迭代器是指向某一节点的,所以其模板参数为KV
	struct RBTreeIterator//也就说迭代器也不知道指向的KV是什么
	{
		typedef RBTreeNode<KV> Node;
		typedef RBTreeIterator<KV, Ref, Ptr> Self;
		
		//普通迭代器
		typedef RBTreeIterator<KV, KV&, KV*> iterator;
		Node* _node;

		RBTreeIterator(Node* node)
			:_node(node)
		{}

		//构造函数接收一个普通迭代器作为参数
		RBTreeIterator(const iterator& it)
			:_node(it._node)
		{}

		//...............省略.............

		
	};

5.完成代码

https://gitee.com/AVine/AVine_Code/tree/master/3_15%20%E5%B0%81%E8%A3%85map%E5%92%8Cset

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小龙向钱进

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值