19.map和set的封装
总的代码会放在最后面
一.set和map源码分析
我们根据这里的map和set发现,他们传入的要么是(key,key)或者是(key,pair(key,T))
第一个模板参数传入的都是key,就第二个模板参数有问题(这个地方是关键)
我们可以发现这个地方和我们写的不一样,这里他用的是一个RBTree进行使用,set和map是通过模板参数进行使用
一个传入的是(key,key) , 另一个传入的是(key,pair<key,T>)
所以说,第一个参数是给find和erase使用的
二.实现set和map的框架
"set实现"#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K>class set{private:RBTree<K,K> _t;};
}
"map实现"#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K,class V>class map{private:RBTree<K,pair<K,V>> _t;};
}
三.插入的复用
#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K>class set{public:bool Insert(const K& key){_t.Insert(key);}private:RBTree<K,K> _t;};
}
#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K,class V>class map{public:bool Insert(const pair<K,V>& kv){_t.Insert(kv);}private:RBTree<K,pair<K,V>> _t;};
}
但是这里我们只要第一个进行比较
所以对于红黑树这一层,我们不知道,传入的到底是key还是pair<>,但是我们的上层知道啊
我们通过传入我们的模板参数,然后进行实例化,拿到值即可
#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K,class V>class map{struct MapKeyOfT{const K& operator()(const pair<K,V>& kv){return kv.first;}};public:bool Insert(const pair<K,V>& kv){_t.Insert(kv);}private:RBTree<K,pair<K,V>,MapKeyOfT> _t;};
}
#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:bool Insert(const K& key){_t.Insert(key);}private:RBTree<K,K,SetKeyOfT> _t;};
}
Insert的实现如下:
bool Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(data);// 新增节点。颜色红色给红色cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while(parent && parent->_col == RED){Node* grandfather = parent->_parent;if(parent == grandfather->_left){// g// p uNode* 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){// g// p u// c// 单旋RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// p u// c//双旋RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{// g// u pNode* 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){// g// u p// c// 单旋RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// u p// c//双旋RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}
本质上就是回调
四.测试代码
void test_set(){set<int> s;int a[] = {4,2,6,1,3,5,15,7,16,14};for(auto e:a){s.insert(e);}}
我们插入一点数据进行测试一下,发现没有报错,那么说明我们模板部分没有写错
五.红黑树迭代器的实现
1.简单 *, !=等操作符 的实现
template <class K,class T>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<K,T> Self;Node* _node;RBTreeIterator(Node* node):_node(node){}T& operator*(){return _node->_data;}bool operator!=(const Self& s){return _node != s._node;}};
这些简单的部分,我们就不做过多的介绍了
2.把迭代器加入到红黑树里面
#pragma once#include "RBTree(copy).h"namespace ltw
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K,K,SetKeyOfT>::iterator iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}bool insert(const K& key){return _t.Insert(key);}private:RBTree<K,K,SetKeyOfT> _t;};void test_set(){set<int> s;int a[] = {4,2,6,1,3,5,15,7,16,14};for(auto e:a){s.insert(e);}}
}
#pragma once#include "RBTree(copy).h"namespace ltw
{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;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}bool insert(const pair<K,V>& kv){return _t.Insert(kv);}private:RBTree<K,pair<K,V>,MapKeyOfT> _t;};
}
3.operator++的重载
我们想一想,红黑树的迭代器进行++,是如何进行++的?
++本质上是在进行中序遍历
Self& operator++(){if(_node->_right){//右不为空,右子树最左节点就是中序的下一个Node* leftMost = _node->_right;while(leftMost&&leftMost->_left){leftMost = leftMost->_left;}_node = leftMost;}else{Node* cur = _node;Node* parent = cur->_parent;while(parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}
这个地方我们的_parent提供了遍历
4.begin()和end()的实现
为了实现范围for,我们还要提供我们的begin()和end()
因为begin()本质上是在找我们中序遍历的第一个,就是最左节点
Iterator Begin(){Node* leftMost = _root;while(leftMost && leftMost->_left){leftMost = leftMost->_left;}return Iterator(leftMost);}
end()的实现:
这里能跑很明显就能看到是中序遍历,符合我们二叉树的性质
void test_map(){map<int,int> s;int a[] = {4,2,6,1,3,5,15,7,16,14};for(auto e:a){s.insert({e,e});}for(const auto& e:s){cout << e.first << " " << e.second << endl;}cout << endl;}
我们看源码这个地方,是增加了一个哨兵位的头节点
这里设计的header的好处是,header和root是互为父子的,这样判断end()的时候,会更加方便
而且,支持反向迭代器更合理一点
5.operator--的实现
operator-- 代码实现Self& operator--(){if(_node->_left){Node* rightMost = _node->_left;while(rightMost&&rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else{//找孩子是父亲右边的那个Node* cur = _node;Node* parent = cur->_parent;while(parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}
但是我们这里的如果是end() (nullptr)传入--,那么就直接奔溃了,所以我们就要做特殊处理
Self& operator--(){if(_node == nullptr){//如果是-- end(),那么就是找到整个树的最后的一个节点(也就是我们的最右节点)Node* rightMost = _root;while(rightMost&&rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else if(_node->_left){Node* rightMost = _node->_left;while(rightMost&&rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else{//找孩子是父亲右边的那个Node* cur = _node;Node* parent = cur->_parent;while(parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}
但是,这样实现还是有缺陷的,这样会面临迭代器失效(这块是一个大坑),这里我们可以采取库里面的方式设计
我们这样也能实现set的反向遍历
set<int>::iterator it = s.end();while(it != s.begin()){--it;cout << *it << " ";}cout << endl;
这里再讲一下我们的迭代器优势(迭代器模式):
6.const迭代器的实现
这里加const迭代器,我们采用的是以前链表的实现方式,代码链接如下:
https://blog.csdn.net/weixin_60668256/article/details/153393453?fromshare=blogdetail&sharetype=blogdetail&sharerId=153393453&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link
测试代码:
void Print(const set<int>& s){set<int>::const_iterator it = s.end();while(it != s.begin()){--it;cout << *it << " ";}}void test_set(){set<int> s;int a[] = {4,2,6,1,3,5,15,7,16,14};for(auto e:a){s.insert(e);}for(const auto& e:s){cout << e << " ";}cout << endl;set<int>::iterator it = s.end();while(it != s.begin()){--it;cout << *it << " ";}cout << endl;Print(s);}
毕竟是树形的结构,如果改变一个节点的值就不一定是搜索树了
,还有一点,就是map的first是不支持修改的,但是map的second是支持修改的,所以我们在这个代码不能直接使用const迭代器
7.Find的实现
Iterator Find(const K& key){Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return Iterator(cur,_root);}}return Iterator(nullptr,_root);}
8.map实现我们的operator[]
map的[]实现,应该依赖我们的insert
所以,我们要进行修改插入函数
pair<Iterator,bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return {Iterator(_root,_root),true};}KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return {Iterator(cur,_root),false};}}cur = new Node(data);Node* newnode = cur;// 新增节点。颜色红色给红色cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while(parent && parent->_col == RED){Node* grandfather = parent->_parent;if(parent == grandfather->_left){// g// p uNode* 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){// g// p u// c// 单旋RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// p u// c//双旋RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{// g// u pNode* 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){// g// u p// c// 单旋RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// u p// c//双旋RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return {Iterator(newnode,_root),true};}
V& operator[](const K& key){pair<iterator,bool> ret = insert({key,V()});return ret.first->second;}
六.map和set总代码实现
"set.h"#pragma once#include "RBTree.h"namespace ltw
{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>::Const_Iterator const_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin()const{return _t.Begin();}const_iterator end()const{return _t.End();}pair<iterator,bool> insert(const K& key){return _t.Insert(key);}iterator find(const K& key){return _t.Find(key);}private:RBTree<K,const K,SetKeyOfT> _t;};void Print(const set<int>& s){set<int>::const_iterator it = s.end();while(it != s.begin()){// *it = 1;--it;cout << *it << " ";}}void test_set(){set<int> s;int a[] = {4,2,6,1,3,5,15,7,16,14};for(auto e:a){s.insert(e);}for(const auto& e:s){cout << e << " ";}cout << endl;set<int>::iterator it = s.end();while(it != s.begin()){// *it = 1;--it;cout << *it << " ";}cout << endl;Print(s);}
}
"map.h"#pragma once#include "RBTree.h"namespace ltw
{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<const K,V>,MapKeyOfT>::Iterator iterator;typedef typename RBTree<K,pair<const K,V>,MapKeyOfT>::Const_Iterator const_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin()const{return _t.Begin();}const_iterator end()const{return _t.End();}pair<iterator,bool> insert(const pair<K,V>& kv){return _t.Insert(kv);}iterator find(const K& key){return _t.Find(key);}V& operator[](const K& key){pair<iterator,bool> ret = insert({key,V()});return ret.first->second;}private:RBTree<K,pair<const K,V>,MapKeyOfT> _t;};void test_map(){map<string,string> dict;dict.insert({"sort","排序"});dict.insert({"left","左边"});dict.insert({"right","右边"});dict["left"] = "right->hahaha";for(const auto& e:dict){cout << e.first << " " << e.second << endl;}cout << endl;map<string,string>::iterator it = dict.begin();while(it != dict.end()){// it->first += 'x';it->second += 'x';cout << it->first << " : " << it->second << endl;++it;}cout << endl;}
}