当前位置: 首页 > news >正文

map_set

前言

在学习了红黑树和AVL树之后,我们了解到红黑树比AVL树更优秀,在底层的选择上很多也是选择红黑树而不是AVL树,本篇博客就围绕map和set封装红黑树的实现上展开讲解,深入学习map和set。

正文

map

map的使用

这部分知识简单,就简单讲解下,主要在后期使用中逐渐掌握,没有必要刻意的背记。

#include <iostream>
#include <map>
using namespace std;void std_map_study()
{//定义map<string, int> dict;//pair类型 定义在std里 一种结构体 map里面的值存储的是pair 这是为了迭代器的方便pair<string, int> p;//插入dict.insert(make_pair("香蕉", 1));//使用函数dict.insert(pair<string, int>("苹果", 1));//使用构造函数dict.insert({ "西瓜",1 }); //列表初始化 和初始化列表两个概念//删除dict.erase("西瓜");//依靠key值删除//[]int ret = dict["香蕉"];//查找auto itt = dict.find("苹果");cout << "查找:" << itt->first << " " << itt->second << endl;//支持范围forcout << "范围for:" << endl;for (auto& p : dict){cout << p.first << " " << p.second << endl;}//迭代器遍历cout << "迭代器遍历:" << endl;auto it = dict.begin();while (it != dict.end()){cout << it->first << " " << it->second << endl;it++;}//不支持sort函数//map迭代器不是随机迭代器 是双向迭代器
}
int main()
{std_map_study();return 0;
}

双向迭代器

map的封装

未封装的红黑树

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;//枚举变量
enum Color
{RED,BLACK
};
//红黑树结点定义
template<class K, class V>
struct RBTreeNode
{RBTreeNode(const pair<K, V> kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_col(RED){}RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;RBTreeNode<K, V>* _left;pair<K, V> _kv; //pair类型Color _col;
};
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, * parent = nullptr;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else return false;}cur = new Node(kv);cur->_col = RED;if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//控制平衡while (parent && parent->_col == RED){Node* grandFather = parent->_parent;if (parent == grandFather->_left){Node* uncle = grandFather->_right;//uncle存在且为黑if (uncle && uncle->_col == RED){//变色parent->_col = uncle->_col = BLACK;grandFather->_col = RED;//继续处理cur = grandFather;parent = cur->_parent;}else //uncle不存在 或者为黑{if (cur == parent->_left) //注意判断是== 不是={RoateR(grandFather);parent->_col = BLACK;grandFather->_col = RED;}else //cur = parent->_right{RoateL(parent);RoateR(grandFather);cur->_col = BLACK;grandFather->_col = RED;}}}else //parent == grandFather->_right{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){RoateL(grandFather);parent->_col = BLACK;grandFather->_col = RED;}else //cur = parent->_left{RoateR(parent);RoateL(grandFather);cur->_col = BLACK;grandFather->_col = RED;}}}//暴力处理_root->_col = BLACK;}return true;}bool CheckColor(Node* root,int blackNum,int benchMark){if (root == nullptr){if (benchMark != blackNum){return false;}return true;}if (root->_col == BLACK){blackNum++;}if (root->_col == RED && root->_parent && root->_parent->_col == RED){cout << root->_kv.first << "连续红色节点" << endl;return false;}return CheckColor(root->_left,blackNum,benchMark) && CheckColor(root->_right, blackNum, benchMark);}bool IsBlance(){return IsBlance(_root);}bool IsBlance(Node* root){if (root == nullptr){return true;}if (root->_col != BLACK){return false;}int benchMark = 0;Node* cur = root;while (cur){if (cur->_col == BLACK){benchMark++;}cur = cur->_left;}return CheckColor(root, 0, benchMark);}
private:Node* _root = nullptr;void RoateL(Node* parent){Node* cur = parent->_right;Node* curLeft = cur->_left;parent->_right = curLeft;if (curLeft){curLeft->_parent = parent;}cur->_left = parent;Node* ppNode = parent->_parent; //记录父节点的父节点parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = cur;}else if (ppNode->_right == parent){ppNode->_right = cur;}cur->_parent = ppNode;}}void RoateR(Node* parent){Node* cur = parent->_left;Node* curRight = cur->_right;parent->_left = curRight;if (curRight){curRight->_parent = parent;}cur->_right = parent;Node* ppNode = parent->_parent; //记录parent->_parent = cur;if (ppNode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = cur;}else if (ppNode->_right == parent){ppNode->_right = cur;}cur->_parent = ppNode;}}
};
封装的红黑树
#pragma once
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;//枚举变量
enum Color
{RED,BLACK
};
//红黑树结点定义
template<class T>
struct RBTreeNode
{RBTreeNode(const T& data):_left(nullptr),_right(nullptr),_parent(nullptr),_data(data),_col(RED){}RBTreeNode<T>* _right;RBTreeNode<T>* _parent;RBTreeNode<T>* _left;T _data; //pair类型Color _col;
};
template<class T,class Ptr,class Ref>
struct  _TreeIterator
{typedef RBTreeNode<T> Node;typedef _TreeIterator<T,Ptr,Ref> Self;typedef _TreeIterator<T, T*, T&> Iterator; //普通迭代器Node* _node;_TreeIterator(const Iterator& it) //支持const迭代器拷贝构造 和普通迭代器构造:_node(it._node){}_TreeIterator(Node* node):_node(node){}Ref operator*() {return _node->_data;}Ptr operator->() {return &_node->_data;}bool operator!=(const Self& s){return s._node != _node;}Self& operator++() //this指针{if (_node->_right){//右树的最左节点Node* subLeft = _node->_right;while (subLeft->_left) //右树肯定存在{subLeft = subLeft->_left;}_node = subLeft;}else //右为空{Node* cur = _node;Node* parent = cur->_parent;while(parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self& operator--(){if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}}else //左为空{ Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}};template<class K, class T,class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;public:typedef _TreeIterator<T,T*,T&> iterator;typedef _TreeIterator<T,const T*,const T&> const_iterator;//反向迭代器 //const修饰的迭代器iterator begin(){Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}iterator end(){return iterator(nullptr);}const_iterator begin() const{Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return const_iterator(leftMin);}const_iterator end() const{return const_iterator(nullptr);}Node* Find(const K& key){KeyOfT kot;Node* cur = _root;while (cur){if (kot(cur->_data) > key){cur = cur->_left;}else if (kot(cur->_data) < key){cur = cur->_right;}else{return cur;}}return nullptr;}pair<iterator,bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}Node* cur = _root, * parent = nullptr;KeyOfT kot;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);cur->_col = RED;Node* newNode = cur;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){Node* uncle = grandFather->_right;//uncle存在且为黑if (uncle && uncle->_col == RED){//变色parent->_col = uncle->_col = BLACK;grandFather->_col = RED;//继续处理cur = grandFather;parent = cur->_parent;}else //uncle不存在 或者为黑{if (cur == parent->_left) //注意判断是== 不是={RoateR(grandFather);parent->_col = BLACK;grandFather->_col = RED;}else //cur = parent->_right{RoateL(parent);RoateR(grandFather);cur->_col = BLACK;grandFather->_col = RED;}}}else //parent == grandFather->_right{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){RoateL(grandFather);parent->_col = BLACK;grandFather->_col = RED;}else //cur = parent->_left{RoateR(parent);RoateL(grandFather);cur->_col = BLACK;grandFather->_col = RED;}}}//暴力处理_root->_col = BLACK;}return make_pair(iterator(newNode), true);}bool CheckColor(Node* root, int blackNum, int benchMark){if (root == nullptr){if (benchMark != blackNum){return false;}return true;}if (root->_col == BLACK){blackNum++;}if (root->_col == RED && root->_parent && root->_parent->_col == RED){cout << root->_kv.first << "连续红色节点" << endl;return false;}return CheckColor(root->_left, blackNum, benchMark) && CheckColor(root->_right, blackNum, benchMark);}bool IsBlance(){return IsBlance(_root);}bool IsBlance(Node* root){if (root == nullptr){return true;}if (root->_col != BLACK){return false;}int benchMark = 0;Node* cur = root;while (cur){if (cur->_col == BLACK){benchMark++;}cur = cur->_left;}return CheckColor(root, 0, benchMark);}
private:Node* _root = nullptr;void RoateL(Node* parent){Node* cur = parent->_right;Node* curLeft = cur->_left;parent->_right = curLeft;if (curLeft){curLeft->_parent = parent;}cur->_left = parent;Node* ppNode = parent->_parent; //记录父节点的父节点parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = cur;}else if (ppNode->_right == parent){ppNode->_right = cur;}cur->_parent = ppNode;}}void RoateR(Node* parent){Node* cur = parent->_left;Node* curRight = cur->_right;parent->_left = curRight;if (curRight){curRight->_parent = parent;}cur->_right = parent;Node* ppNode = parent->_parent; //记录parent->_parent = cur;if (ppNode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = cur;}else if (ppNode->_right == parent){ppNode->_right = cur;}cur->_parent = ppNode;}}
};
两者的差异

pair的调用

KeyOfT

迭代器

迭代器外部包装实现

map迭代器,我们要明确一点就是是否可是对key值改变。我们知道key值是唯一的,而且如果你的key值可以被改变的话,那么如何保证他的有序性呢?代码就是再灵活,你把key值都改了,那我咋办。所以,map的key值是唯一不可变。无论迭代器是否加const,他都不可以改变,const的迭代器,是连value值也不能变。

迭代器重点

_TreeIterator(const Iterator& it) :_node(it._node)
{}

看一下这个迭代器是干什么用的,再看一下如下的代码为什么能成功运行

#include <iostream>
//#include "RBTree.h"
//#include <vector>
#include <map>
using namespace std;int main()
{map<string, string> dict;map<string, string>::const_iterator it = dict.begin(); //普通迭代器 ->const迭代器return 0;
}

这里能成功运行是因为,调用了迭代器的构造函数,注意是构造函数不是拷贝构造,这里两者类型不同,不同类型的初始化另一方对象,调用的是构造函数。

再看一下这里

大家觉得,这段代码,会调用上面那个构造函数吗?答案是,不会,注意,我们上面那个迭代器的定义是一个普通的迭代器,和红黑树里面那个是一样的。

这里返回的是一个const迭代器,const迭代器不能传值给一个普通迭代器呀,从形参类型看就不能呀。所以,这里是调用了默认的构造函数。但是,编译器会优化,其实就是一步构造函数初始化,根本不会让你连续构造两次。

这里为啥要定义成一个普通的迭代器呢?这里定义成普通的迭代器,对于普通迭代器初始化普通迭代器,就是拷贝构造函数。对于普通迭代器初始化const迭代器就是构造函数,一举两得。对于这里,这个函数的主要功能就是把普通迭代器转换成const迭代器,注意是单向的。const迭代器无法转换成普通迭代器,形参就无法接受。

再看一下,下面这段代码

que::map<int, int>::iterator it = m1.begin(); //m1(非const)

这段代码,本应该是调用上面那个构造函数的,但是编译器做了优化,直接一步构造

注意看,这里的指针是一样的

[ ]括号实现

只有map才会由[ ]实现,他的模型是key_value。使用key值,返回value。set只有key,不需要[]实现。

注意这里编译器应该会优化,但不过优化的对象是pair对象,可能pair不会产生临时对象,直接就去初始化ret对象内部迭代器,调用拷贝构造。

set

set的使用

void std_set_test()
{//set的定义set<string> s;//插入s.insert("string");s.insert({ "int" }); //列表初始化(c++11) 和初始化列表(c++98)两个概念//删除s.erase("int");//查找auto it = s.find("int");if (it == s.end()) cout << "无int" << endl;//范围forfor (auto& str : s) cout << str << endl;//迭代器auto it1 = s.begin();while (it1 != s.end()){cout << *it1;it1++;}//不支持sort函数//set迭代器不是随机迭代器 是双向迭代器//sort(s.begin(), s.end());
}
int main()
{std_set_test();return 0;
}

双向迭代器不支持sort函数

set的封装

#pragma once
#include "RBTree.h"
namespace que
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;//typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;iterator begin() const{return _t.begin();}iterator end() const{return _t.end();}pair<iterator,bool> Insert(const K& k) //这里不可以加const解决 加了const还咋insert数据{pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(k);return pair<iterator, bool>(ret.first, ret.second);//return _t.Insert(k); //这里正常调用的是一个没有const修饰的迭代器 }private:RBTree<K, K,SetKeyOfT> _t;};
}

SetKeyOfT 方便find返回值

struct SetKeyOfT{const K& operator()(const K& key){return key;}};

迭代器

set迭代器和map迭代器是一个模板,但是有一个不同的是,set实际上是key_key结构,他只有一个泛型,就是key值,唯一不可变。所以,set的迭代器无论是const版本还是非const版本,都是一样的,因为他的唯一的值就是key。所以,在set里封装好的迭代器都是const版本的迭代器,只不过是名字不同而已。

typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;

迭代器重点

逻辑图(map/set)

逻辑结构

物理结构

总结

map和set封装在本篇博客大体已讲完,涉及到红黑树具体细节,可查看我的博客(红黑树)RBT红黑树(c++)-CSDN博客

本篇博客并没有涉及反向迭代器器,只涉及到正向迭代器。可查看我的博客(涉及反向迭代器设计)

STL_stack和queue(deque priority_queue) _stl stack queue-CSDN博客

http://www.dtcms.com/a/346173.html

相关文章:

  • Trie 树(字典树)
  • Rust 入门 注释和文档之 cargo doc (二十三)
  • 51单片机-中断系统
  • 【数据分享】各省及全国GDP增长指数(1980-2022)
  • 彻底解决 Windows 文件扩展名隐藏问题,注册表修改显示文件后缀方法
  • More Effective C++ 条款01:仔细区别 pointers 和 references
  • 构建城市数字孪生底座:深度解析智慧城市全景视频拼接融合解决方案
  • constraint_mode使用
  • 【Python】两条命令永久切国内源
  • Android 16环境开发的一些记录
  • C语言中的CSI_START和CSI_END宏
  • 拿到手一个前端项目,应该如何启动
  • 多目标跟踪中基于目标威胁度评估的传感器控制方法复现
  • lanczos算法学习笔记
  • 【GM3568JHF】FPGA+ARM异构开发板 测试命令
  • OFD格式文件及Python将PDF转换为OFD格式文件
  • Informer参数代码
  • SPI的DMA方式
  • 线性回归:从原理到实战的完整指南
  • ROS中的自定义消息
  • Windows 11 安装 Miniforge,配置国内源
  • 基层医疗遇到了什么问题?
  • 【spring security】权限管理组件执行流程详解
  • centos7安装oracle19c流程(自用)
  • Highcharts 推出适用于 Svelte 的官方集成库
  • 【软考架构】关系数据库
  • 无人机电机与螺旋桨的匹配原理及方法(一)
  • 随机森林--集成学习
  • 华为网路设备学习-29(BGP协议 四)路由策略-实验
  • 虚拟线程(高版本JDK)