前言:
C++中的map
是标准模板库(STL)中的一种关联容器,它存储的是键值对(key-value pairs),其中每个键都是唯一的。
map的特点
**值唯一性:**map中的每个键只能出现一次,如果尝试插入具有相同键的新元素,则会覆盖原有键对应的值。自动排序:map中的元素是根据键值自动排序的,默认情况下是按照键的升序排序。动态调整:插入和删除操作会自动调整内部结构以保持有序性和平衡性。支持复杂数据类型:map的键和值可以是任意数据类型,包括自定义类型。迭代器支持:map提供双向迭代器,可以遍历容器中的所有元素。**成员函数丰富:**map提供了一系列成员函数,如insert、erase、find、count、begin、end等,用于执行各种操作。空间和性能开销:由于使用红黑树,map可能会有较大的空间开销,并且相比于哈希表(如unordered_map),插入和删除操作的时间复杂度为对数级别,可能在某些高性能要求的应用中不如哈希表高效map的实现 参考:红黑树
map的存储结构
由于set和map是公用一棵树,set是K 、map是KV的结构,为了适应map的结构,set做出一定的改变内部类是为了取到map内所存储的数据在set的map中 set所存储的是key而map是pair。这里取到的值是first。template<class K, class V> class map { struct mapofT { const K& operator()(const pair<K, V>& kv) { return kv.first; } }; public: private: RBTree<K, pair<const K, V>, mapofT> _t; };
map的插入
插入实现的基本步骤
查找插入位置**:map内部使用红黑树来维护元素的顺序,因此插入操作首先需要在树中找到正确的位置。这通常涉及到比较键值并沿着树进行遍历。
**创建节点:**一旦找到了插入位置,就会创建一个新的节点来存储要插入的键值对。
**插入节点:**新创建的节点会被插入到红黑树中的正确位置,这可能涉及到树的旋转和重新着色操作,以保持红黑树的平衡性质。
**返回插入结果:**insert函数返回一个pair,其中第一个元素是一个迭代器,指向新插入的元素(如果键不存在),或者指向已存在键的元素;第二个元素是一个布尔值,指示插入是否成功(即键是否不存在)。
pair<iterator,bool> insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}Node* parent = nullptr;Node* cur = _root;keyofT kot;while (cur){if (kot(data) > kot(cur->_data)){parent = cur;cur = cur->_right;}else if (kot(data) < kot(cur->_data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(data) < kot(parent->_data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandparent = parent->_parent;if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else//uncle is not or black{if (cur == parent->_left){RotateR(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateL(parent);RotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;}break;}}else//parent == grandparent->_right{Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){grandparent->_col = RED;parent->_col = uncle->_col = BLACK;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}}break;}}_root->_col = BLACK;return make_pair(iterator(newnode),true );}
map的查找
调用find
成员函数,传入要查找的键作为参数。find
函数在内部遍历红黑树,使用键值进行比较,寻找匹配的元素。如果找到了匹配的键,find
返回一个指向该元素的迭代器。如果没有找到匹配的键,find
返回end()
迭代器。红黑树的查找类似于,AVL的查找。本质上是一样的。 Node* find(const T& data){ keyofT kot; Node* cur = _root; while (cur) { if (kot(data) > kot(cur->_data)) { cur = cur->_right; } else if (kot(data) < kot(cur->_data)) { cur = cur->_left; } else { return cur; } } return nullptr;}
map重载[]
STL中也是调用insert。传入K返回V的形式。V& operator[] (const K& key){ pair<iterator, bool> ret = insert(make_pair(key,V())); return ret.first->second;}
map的迭代器
C++中的map是一个关联容器,它存储键值对(key-value pairs),并且根据键(key)来快速检索值(value)。map的迭代器是一种指针,指向map中的元素。map的迭代器有两种类型:const_iterator和iterator。const_iterator用于只读访问,而iterator可以读写。
迭代器的特性
map
的迭代器遵循双向迭代器的要求,可以向前和向后遍历。
迭代器在map
被修改时(例如插入或删除操作)可能会失效。
map
的迭代器可以通过解引用操作符(*
)来访问指向的元素,或者使用箭头操作符(->
)来访问元素的成员。
set迭代器类似于list的迭代器
迭代器的封装
主要区别在于++
和--
Ptr是T*,Ref是T&,设置这么多的模板参数是为适配出const的迭代器 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(Node* node):_node(node){}TreeIterator(const Iterator& it):_node(it._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;}};
前置++
前置++ 的本质上就是中序的遍历,左子树-根-右子树如果右子树存在就去右子树的最左节点_node 不是右节点那么,证明子树的左右节点均访问完成,需要访问祖父的节点self& operator++(){ if (_node->_right) { Node* cur = _node->_right; while (cur->_left) { cur = cur->_left; } _node = cur; } else { Node* cur = _node; Node* parent = _node->_parent; while (parent) { if (cur == parent->_left) { break; } else { cur = cur->_parent; parent = parent->_parent; } } _node = parent; } return *this;}
前置–
前置-- 是前置++的镜像的一个顺序的访问,右子树-根-左子树方法是类似于前置++self& operator--(){if (_node->_left){Node* cur = _node->_right;while (cur->_left){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;while (parent && parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
迭代器
C++中的map是一种关联容器,它存储键值对(key-value pairs),并且按照键的顺序自动排序。map的迭代器用于遍历容器中的元素。map提供了多种迭代器成员函数,包括:
**begin():**返回指向map中第一个元素的迭代器。
**end():**返回指向map容器末尾位置的迭代器,这个位置不包含任何元素,用作遍历结束的标志。
**rbegin():**返回指向map最后一个元素的反向迭代器。
**rend():**返回指向map第一个元素的反向迭代器。
map的迭代器是const_iterator类型的,这意味着它们提供对元素的只读访问。如果需要修改元素,可以使用iterator类型
map的迭代器提供了向前和向后遍历的能力,但不支持随机访问迭代器的所有操作,如算术运算
前面是将迭代器封装,因为正常的++或者–已不可以支持自定义类型的加减
在红黑树的类中实现,在实现set时候只需要调用,在这里面可以认为红黑树是容器的适配器
typedef TreeIterator<T, T*, T&> iterator;typedef TreeIterator<T,const T*,const T&> const_iterator;iterator begin(){ Node* leftmin = _root; while (leftmin->_left) { leftmin = leftmin->_left; } return iterator(leftmin);}iterator end(){ return iterator(nullptr);}const_iterator begin()const { Node* leftmin = _root; while (leftmin->_left) { leftmin = leftmin->_left; } return const_iterator(leftmin);}const_iterator end()const { return const_iterator(nullptr);}
源码
map
#pragma once#include"RBTree.h"#include<iostream>using namespace std;namespace Map{template<class K, class V>class map{struct mapofT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, mapofT>::iterator iterator;typedef typename RBTree<K, pair<const K, V>, mapofT>::const_iterator const_iterator;V& operator[] (const K& key){pair<iterator, bool> ret = insert(make_pair(key,V()));return ret.first->second;}pair<iterator,bool> insert(const pair<K,V>& kv){return _t.insert(kv);}iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin()const{return _t.begin();}const_iterator end()const{return _t.end();}private:RBTree<K, pair<const K, V>, mapofT> _t;};}
红黑树
#pragma once#include<iostream>#include<assert.h>#include<utility>using namespace std;enum Colour{RED,BLACK};template< class T>class RBTreeNode{public:RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Colour _col;RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _data(data){}}; 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(Node* node):_node(node){}TreeIterator(const Iterator& it):_node(it._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->_left){Node* cur = _node->_right;while (cur->_left){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;while (parent && parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}self& operator++(){if (_node->_right){Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;while (parent){if (cur == parent->_left){break;}else{cur = cur->_parent;parent = parent->_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;iterator begin(){Node* leftmin = _root;while (leftmin->_left){leftmin = leftmin->_left;}return iterator(leftmin);}iterator end(){return iterator(nullptr);}const_iterator begin()const {Node* leftmin = _root;while (leftmin->_left){leftmin = leftmin->_left;}return const_iterator(leftmin);}const_iterator end()const {return const_iterator(nullptr);}Node* find(const T& data){keyofT kot;Node* cur = _root;while (cur){if (kot(data) > kot(cur->_data)){cur = cur->_right;}else if (kot(data) < kot(cur->_data)){cur = cur->_left;}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* parent = nullptr;Node* cur = _root;keyofT kot;while (cur){if (kot(data) > kot(cur->_data)){parent = cur;cur = cur->_right;}else if (kot(data) < kot(cur->_data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(data) < kot(parent->_data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandparent = parent->_parent;if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else//uncle is not or black{if (cur == parent->_left){RotateR(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateL(parent);RotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;}break;}}else//parent == grandparent->_right{Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){grandparent->_col = RED;parent->_col = uncle->_col = BLACK;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}}break;}}_root->_col = BLACK;return make_pair(iterator(newnode),true );}void RotateR(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{ppnode->_right = cur;}cur->_parent = ppnode;}}void RotateL(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{ppnode->_right = cur;}cur->_parent = ppnode;}}bool is_balance(){return is_balance(_root);}bool Checknum(Node* root, int blacknum, int stdnum){if (root == nullptr){if (blacknum != stdnum){return false;}return true;}if (root->_col == BLACK){++blacknum;}return Checknum(root->_left, blacknum, stdnum)&& Checknum(root->_right, blacknum, stdnum);}bool is_balance(Node* root){if (root == nullptr){return true;}if (root->_col == RED){return false;}int stdnum = 0;Node* cur = root;while (cur){if (cur->_col == BLACK){++stdnum;}cur = cur->_left;}return Checknum(root, 0, stdnum);}private:Node* _root = nullptr;};