回顾:之前我们一起学习了map,set,multimap,multiset的接口和相关介绍map和se详细介绍
还实现了AVL树以及RB树,旋转,旋转+变色相信大家已经很熟悉啦手撕AVL和红黑树
本文将带大家一起封装map和set
目录
1.找到方向
2.迭代器最重要的部分
3.set迭代器和map迭代器
4.我的实现
5.源码
1.找到方向
首先 我们在实现之前要了解库里面实现的逻辑是什么
也就是对于set,红黑树的节点模板参数只有K,对于map,红黑树节点的模版参数是pair<const K,V>
第一个模板参数为了拿到单独的K类型(相当于索引) 因为find,erase这些接口函数的参数是K
第二个模版参数决定了树的节点里面存什么——K or KV(索引到的结果)
所以我们直接把第二个模板参数改成T,对于set T就是K,对于map T就是pair<const K,V>
2.迭代器最重要的部分
begin应该在树中序的第一个,也就是左子树的最后一个节点
end这里我们为了简单 就给成nullptr 但是库里面使用哨兵头节点
库里面的end:对end()位置的迭代器进行--操作,必须要能找最后一个元素,最好的方式是将end()放在头结点的位置
迭代器的++怎么操作?
Self& operator++() {if (_node->_right) {//1.右不是空 下一个就是右子树的最左节点node* subL = _node->_right;while (subL->_left) {subL = subL->_left;}_node = subL;}else {//2.右为空 当前子树完了 沿着到根的路径 找孩子是父亲左的那个祖先node* cur = _node;node* parent = cur->_parent;while (parent && cur == parent->_right) {cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
++要根据中序 左——根——右
看右子树是不是空 如果是说明当前右子树的根 这一支走完了
要找到这一支的根
只要用一个parent前驱保存一下
--当然是相反的操作
Self& operator--() {if (_node->_left) {//1.左不是空 下一个就是左子树的最右节点node* subR = _node->_left;while (subR->_right) {subR = subR->_right;}_node = subR;}else {//2.左为空 找孩子是父亲的右的那个祖先node* cur = _node;node* parent = cur->_parent;while (parent && cur == parent->_left) {cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
3.set迭代器和map迭代器
set的K不能修改 但是现在实现的迭代器居然可以修改!!!
看了库之后发现set的普通迭代器都是const实现的
那么我们跟着改一下啦~~
但是这样报错了
- 报错的原因
_t是一个普通的树 普通对象调用begin返回普通的迭代器
但是在set中我们的普通迭代器都是用const迭代器实现的
所以出现了问题 根本没有从普通迭代器到const迭代器的构造
报错原因:
编译器看到是一个普通迭代器转换成一个const迭代器 认为这里是类型转换
类型转换可以依赖单参数的构造函数
所以他去匹配
这个构造 没办法把一个普通迭代器转化成node类型
- 大佬是这样解决
这个函数到底实现的拷贝构造还是构造 取决于类模板被实例化成什么
因为被实例化成const迭代器的时候 传入的就是const& const* 也就是Ref接受了const& Ptr接受了const*
在set中 类模板中iterator就是被实例化成const迭代器 所以就可以实现从普通迭代器到const迭代器的构造
反观map,应该是k不能改 v可以修改
因为pair帮我们把K给const 迭代器都是正常的
4.我的实现
仓库里有代码
RBTree.h
#pragma once
#include "标头.h"
enum Colour {RED,BLACK,
};
template<class T>
struct RBNode {RBNode<T>* _left;RBNode<T>* _right;RBNode<T>* _parent;T _data;Colour _col;RBNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr),_col(RED),_data(data){}
};
template <class T,class Ref,class Ptr>
struct __RBTreeIterator {typedef RBNode<T> node;typedef __RBTreeIterator<T, Ref, Ptr> Self;node* _node;__RBTreeIterator(node* node) :_node(node){}__RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it) //注意这个不是拷贝构造 相当于传入普通迭代器最后返回:_node(it._node){}Ref operator*(){return _node->_data;}Ptr operator->() {return &_node->_data;}bool operator!=(const Self& s) {return _node != s._node;}Self& operator++() {if (_node->_right) {//1.右不是空 下一个就是右子树的最左节点node* subL = _node->_right;while (subL->_left) {subL = subL->_left;}_node = subL;}else {//2.右为空 当前子树完了 沿着到根的路径 找孩子是父亲左的那个祖先node* cur = _node;node* parent = cur->_parent;while (parent && cur == parent->_right) {cur = parent;parent = parent->_parent;}_node = parent;}return *this;}Self& operator--() {if (_node->_left) {//1.左不是空 下一个就是左子树的最右节点node* subR = _node->_left;while (subR->_right) {subR = subR->_right;}_node = subR;}else {//2.左为空 找孩子是父亲的右的那个祖先node* cur = _node;node* parent = cur->_parent;while (parent && cur == parent->_left) {cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
};template<class K, class T,class KeyofT>
class RBTree
{
public:typedef RBNode<T> node;~RBTree(){_Destroy(_root);_root = nullptr;}
public:typedef __RBTreeIterator<T, T&, T*> iterator;typedef __RBTreeIterator<T, const T&,const T*> const_iterator;iterator begin() {node* cur = _root;while (cur && cur->_left) {cur = cur->_left;}return iterator(cur);}iterator end() {return iterator(nullptr);}const iterator begin() const {node* cur = _root;while (cur && cur->_left) {cur = cur->_left;}return iterator(cur);}const iterator end() const {return iterator(nullptr);}node* Find(const K& key){node* cur = _root;KeyofT kot;while (cur) {if (kot(cur->_data) < key) {cur = cur->_right;}else if (kot(cur->_data) > key) {cur = cur->_left;}else return cur;}return nullptr;}void RotateL(node* pre) {//subR subRL pp//pre_bf = 2 && cur_bf = 1//要注意的是subRL可能是空 pre的pre可能是空(此时检索到根节了)node* subR = pre->_right;node* subRL = subR->_left;pre->_right = subRL;if (subRL) subRL->_parent = pre;node* pp = pre->_parent;subR->_left = pre;pre->_parent = subR;if (pp == nullptr) {_root = subR;_root->_parent = nullptr;}else {if (pp->_left == pre) {pp->_left = subR;}else {pp->_right = subR;}subR->_parent = pp;}}void RotateR(node* pre) {//subL subLR pp//pre_bf=-2 cur_bf=-1node* subL = pre->_left;node* subLR = subL->_right;pre->_left = subLR;if (subLR) subLR->_parent = pre;node* pp = pre->_parent;subL->_right = pre;pre->_parent = subL;if (pre == _root) {_root = subL;_root->_parent = nullptr;}else {if (pp->_left == pre) pp->_left = subL;else pp->_right = subL;subL->_parent = pp;}}bool IsBalance() {if (_root && _root->_col == RED) {cout << "根节点颜色是红色" << endl;return false;}int benchmark = 0;node* cur = _root;while (cur) {if (cur->_col == BLACK) ++benchmark;cur = cur->_left;}return _Check(_root, 0, benchmark);}int Height(){return _Height(_root);}pair<iterator, bool> Insert(const T& data){if (_root == nullptr){_root = new node(data);_root->_col = BLACK;return make_pair(iterator(_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 make_pair(iterator(cur), false);}}cur = new node(data);node* newnode = cur;if (kot(parent->_data) > kot(data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent && parent->_col == RED){node* grandfather = parent->_parent;if (grandfather->_left == parent){node* uncle = grandfather->_right;// 情况1:u存在且为红,变色处理,并继续往上处理if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;// 继续往上调整cur = grandfather;parent = cur->_parent;}else // 情况2+3:u不存在/u存在且为黑,旋转+变色{// g// p u// c if (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// p u// cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;//parent->_col = RED;grandfather->_col = RED;}break;}}else // (grandfather->_right == parent){// g// u p// cnode* uncle = grandfather->_left;// 情况1:u存在且为红,变色处理,并继续往上处理if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;// 继续往上调整cur = grandfather;parent = cur->_parent;}else // 情况2+3:u不存在/u存在且为黑,旋转+变色{// g// u p// cif (cur == parent->_right){RotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{// g// u p// cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(iterator(newnode), true);;}
private:void _Destroy(node* root){if (root == nullptr){return;}_Destroy(root->_left);_Destroy(root->_right);delete root;}int _Height(node* root){if (root == NULL)return 0;int leftH = _Height(root->_left);int rightH = _Height(root->_right);return leftH > rightH ? leftH + 1 : rightH + 1;}bool _Check(node* root, int blacknum, int benchmark){if (root == nullptr) {if (benchmark != blacknum) {cout << "某条路上黑节点数量不等" << endl;return false;}return true;}if (root->_col == BLACK) {++blacknum;}if (root->_col == RED && root->_parent && root->_parent->_col==RED) {cout << "存在连续红色" << endl;return false;}return _Check(root->_left, blacknum, benchmark) && _Check(root->_right, blacknum, benchmark);}private:node* _root=nullptr;
};
map.h
#pragma once
#include "RBTree.h"
namespace wrt {template<class K,class V>class map{public:struct MapKeyofT {const K& operator()(const pair<const K,V>& kv) {return kv.first;}};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();}V& operator[](const K& key){pair<iterator,bool> ret=_t.Insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<const K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>,MapKeyofT> _t;};void test_map1(){map<string, string> dict;dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("count", "计数"));dict.insert(make_pair("string", "字符"));//插入失败map<string, string>::iterator it = dict.begin();while (it != dict.end()){cout << it->first << ":" << it->second << endl;it->first = "sdh";it->second = "222";++it;}cout << endl;for (auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}cout << endl;}void test_map2(){string arr[] = { "hello","hello","hi"};map<string, int> countMap;for (auto& e : arr){countMap[e]++;}for (auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}}}
set.h
#pragma once
#include "RBTree.h"
namespace wrt {template<class K>class set {struct SetKeyofT {const K& operator()(const K& key) {return key;}};public://编译器无法识别RBTree<K, K, SetKeyofT>是一个静态变量还是一个类型//类模板里面取RBTree<K, K, SetKeyofT> 一定要加上typename //目的是告诉编译器这是一个类型 等类模板实例化之后再去取这个类型//由于set不能修改K也就是value 普通迭代器也是用const迭代器实现的typedef typename RBTree<K, K, SetKeyofT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyofT>::const_iterator const_iterator;iterator begin(){//但是这里有一个编译错误return _t.begin();}iterator end() {return _t.end();}pair<iterator, bool> insert(const K& key){return _t.Insert(key);}private:RBTree<K,K,SetKeyofT> _t;};void test_set() {set<int> s;int a[] = {4,1,7,88,5,2,6,4,7,8,2,3,0};for (auto e : a) {s.insert(e);}set<int>::iterator it= s.begin();while (it != s.end()) {cout << *it << " ";//*it=1;++it;}cout << endl;}
}
5.源码
源码在这里