C++中map和set封裝實現(xiàn)示例
mao和set模擬實現(xiàn)
STL map和set只是包含了幾個頭文件

主要在選中的這個文件里,打開之后我們可以看到紅黑樹

用紅黑樹實現(xiàn)map和set

set的主要實現(xiàn)

set里面的value type和key type都是KEY

map里面的value type是pair,key type是KEY
這里用一顆泛型結(jié)構(gòu)的RBTree,通過不同的實例化參數(shù),實現(xiàn)出了map和set。
模擬實現(xiàn)
這里不用說明紅黑樹是K還是KV,用T來決定紅黑樹,使用時T是什么,紅黑樹就是什么


如Map傳的是pair,T就是pair,Set傳的是K,T就是K


T傳給了節(jié)點里面的data,上面?zhèn)鲄鱇的原因是find函數(shù)要用到,find是通過K去進行查找。
Insert插入數(shù)據(jù)的時候要比較數(shù)據(jù)的大小選擇合適的位置插入,但這里data是T類型,對于set可直接比較,而map傳過來的是pair,如果比較pair就要比較first和second,這種不滿足我們的需求,因為比較的時候既要滿足set也要滿足Map.
我們用仿函數(shù)來滿足這種要求,這里仿函數(shù)是把T里面的k取出來,pair的K就是first

取K的仿函數(shù)

對于set而言,直接返回就行
對于map而言,就要取first

之后修改rbtree.h,創(chuàng)建一個仿函數(shù)對象,這個對象是什么類型的就根據(jù)什么類型取比較即可

Insert
對于Map而言,_t是RBTree類型,Map的insert只需調(diào)用紅黑樹的Insert即可

set也一樣

迭代器
迭代器也依靠紅黑樹的迭代器實現(xiàn),tyoename作用,告訴編譯器是要把類型進行重命名

以下是紅黑樹的迭代器
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
{}
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator//迭代器
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)//構(gòu)造
:_node(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;
}
};

begin和end
template<class K, class T, class KeyOfT>
struct RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __RBTreeIterator<T, T&, T*> iterator;
iterator begin()
{
Node* left = _root;
while (left && left->_left)
{
left = left->_left;
}
return iterator(left);
}
iterator end()
{
return iterator(nullptr);
}
};begin是找最左邊的節(jié)點,這里的_root是紅黑樹的根節(jié)點,end是最后一個節(jié)點的下一個位置就是空。
++和--
這里++和--是按照中序進行的
這里訪問順序是左根右
1.如果右子樹不為空,++就是找右子樹中序的第一個(最左節(jié)點)
2.右子樹是空,++找孩子不是父親右的那個父親
第二句話理解,這里7訪問完,父親是6,7是6右子樹,更新cur,parent,8是parent,6是cur,cur不是parent右子樹。所以下一個節(jié)點是8

--是反向左子樹
右根左
1.如果左子樹不為空,我們就訪問它的最右節(jié)點
2.如果為空,訪問孩子不是父親的左的父親
Self& operator++()
{
if (_node->_right)
{
// 下一個就是右子樹的最左節(jié)點
Node* left = _node->_right;
while (left->_left)
{
left = left->_left;
}
_node = left;
}
else
{
// 找祖先里面孩子不是祖先的右的那個
Node* parent = _node->_parent;
Node* cur = _node;
while (parent && cur == parent->_right)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
if (_node->_left)
{
// 下一個是左子樹的最右節(jié)點
Node* right = _node->_left;
while (right->_right)
{
right = right->_right;
}
_node = right;
}
else
{
// 孩子不是父親的左的那個祖先
Node* parent = _node->_parent;
Node* cur = _node;
while (parent && cur == parent->_left)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}operator[]
[]的實現(xiàn)要改造一個迭代器

map和set的insert也做修改


只有map有[],我們不需要在紅黑樹里面實現(xiàn)[],單獨給map實現(xiàn)即可

ret.first是迭代器,->second是KV的value
Map中使用方括號訪問鍵對應(yīng)的值map[key]時:
- 若該key存在,則訪問取得value值;
- 若該key不存在,訪問仍然成功,取得value對象默認構(gòu)造的值。具體如下:
用 []訪問,但key不存在時,C++會利用該key及默認構(gòu)造的value,組成{key,value}對,插入到map中。
value為 string對象,則構(gòu)造空串;value為int對象,構(gòu)造為0。

范圍for也可以使用

完整代碼
set.h
#include"rbtree.h"
namespace myspace
{
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();
}
pair<iterator, bool> insert(const K& key)
{
return _t.Insert(key);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
void test_set()
{
set<int> s;
set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
s.insert(3);
s.insert(2);
s.insert(1);
s.insert(5);
s.insert(3);
s.insert(6);
s.insert(4);
s.insert(9);
s.insert(7);
it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
}map.h
#include"rbtree.h"
#pragma once
namespace myspace
{
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();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
void test_map()
{
string arr[] = { "蘋果", "西瓜", "蘋果", "西瓜", "蘋果", "蘋果", "西瓜", "蘋果", "香蕉", "蘋果", "香蕉" };
map<string, int> countMap;
for (auto& str : arr)
{
// 1、str不在countMap中,插入pair(str, int()),然后在對返回次數(shù)++
// 2、str在countMap中,返回value(次數(shù))的引用,次數(shù)++;
countMap[str]++;
}
map<string, int>::iterator it = countMap.begin();
while (it != countMap.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
for (auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
}
}rbtree.h
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
{}
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)
:_node(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->_right)
{
// 下一個就是右子樹的最左節(jié)點
Node* left = _node->_right;
while (left->_left)
{
left = left->_left;
}
_node = left;
}
else
{
// 找祖先里面孩子不是祖先的右的那個
Node* parent = _node->_parent;
Node* cur = _node;
while (parent && cur == parent->_right)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
if (_node->_left)
{
// 下一個是左子樹的最右節(jié)點
Node* right = _node->_left;
while (right->_right)
{
right = right->_right;
}
_node = right;
}
else
{
// 孩子不是父親的左的那個祖先
Node* parent = _node->_parent;
Node* cur = _node;
while (parent && cur == parent->_left)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
};
template<class K, class T, class KeyOfT>
struct RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __RBTreeIterator<T, T&, T*> iterator;
iterator begin()
{
Node* left = _root;
while (left && left->_left)
{
left = left->_left;
}
return iterator(left);
}
iterator end()
{
return iterator(nullptr);
}
pair<iterator, bool> Insert(const T& data)
{
KeyOfT kot;
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
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;
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* grandfater = parent->_parent;
assert(grandfater);
assert(grandfater->_col == BLACK);
// 關(guān)鍵看叔叔
if (parent == grandfater->_left)
{
Node* uncle = grandfater->_right;
// 情況一 : uncle存在且為紅,變色+繼續(xù)往上處理
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfater->_col = RED;
// 繼續(xù)往上處理
cur = grandfater;
parent = cur->_parent;
}// 情況二+三:uncle不存在 + 存在且為黑
else
{
// 情況二:右單旋+變色
// g
// p u
// c
if (cur == parent->_left)
{
RotateR(grandfater);
parent->_col = BLACK;
grandfater->_col = RED;
}
else
{
// 情況三:左右單旋+變色
// g
// p u
// c
RotateL(parent);
RotateR(grandfater);
cur->_col = BLACK;
grandfater->_col = RED;
}
break;
}
}
else // (parent == grandfater->_right)
{
Node* uncle = grandfater->_left;
// 情況一
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfater->_col = RED;
// 繼續(xù)往上處理
cur = grandfater;
parent = cur->_parent;
}
else
{
// 情況二:左單旋+變色
// g
// u p
// c
if (cur == parent->_right)
{
RotateL(grandfater);
parent->_col = BLACK;
grandfater->_col = RED;
}
else
{
// 情況三:右左單旋+變色
// g
// u p
// c
RotateR(parent);
RotateL(grandfater);
cur->_col = BLACK;
grandfater->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
if (_root == nullptr)
{
return true;
}
if (_root->_col == RED)
{
cout << "根節(jié)點不是黑色" << endl;
return false;
}
// 黑色節(jié)點數(shù)量基準值
int benchmark = 0;
/*Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
++benchmark;
cur = cur->_left;
}*/
return PrevCheck(_root, 0, benchmark);
}
private:
bool PrevCheck(Node* root, int blackNum, int& benchmark)
{
if (root == nullptr)
{
//cout << blackNum << endl;
//return;
if (benchmark == 0)
{
benchmark = blackNum;
return true;
}
if (blackNum != benchmark)
{
cout << "某條黑色節(jié)點的數(shù)量不相等" << endl;
return false;
}
else
{
return true;
}
}
if (root->_col == BLACK)
{
++blackNum;
}
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "存在連續(xù)的紅色節(jié)點" << endl;
return false;
}
return PrevCheck(root->_left, blackNum, benchmark)
&& PrevCheck(root->_right, blackNum, benchmark);
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subR;
}
else
{
ppNode->_right = subR;
}
subR->_parent = ppNode;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subL;
}
else
{
ppNode->_right = subL;
}
subL->_parent = ppNode;
}
}
private:
Node* _root = nullptr;
};總結(jié)
到此這篇關(guān)于C++中map和set封裝實現(xiàn)的文章就介紹到這了,更多相關(guān)C++ map和set封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++用一棵紅黑樹同時封裝出set與map的實現(xiàn)代碼
- C++使用一棵紅黑樹同時封裝出map和set實例代碼
- C++ map與set封裝實現(xiàn)過程講解
- C++深入探究哈希表如何封裝出unordered_set和unordered_map
- c++容器list、vector、map、set區(qū)別與用法詳解
- C++ STL入門教程(7) multimap、multiset的使用
- C++中map和set的簡介及使用詳解
- C++中set/multiset與map/multimap的使用詳解
- C++中map和set的使用詳細攻略
- C++中常見容器類的使用方法詳解(vector/deque/map/set)
- C++實現(xiàn)map和set封裝詳解
相關(guān)文章
C語言中單鏈表(不帶頭結(jié)點)基本操作的實現(xiàn)詳解
鏈表是一種物理存儲結(jié)構(gòu)上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。本文主要和大家聊聊C語言中單鏈表(不帶頭結(jié)點)的基本操作,感興趣的小伙伴可以了解一下2022-11-11
C語言數(shù)據(jù)結(jié)構(gòu)與算法之單鏈表
單鏈表是一種鏈式存取的數(shù)據(jù)結(jié)構(gòu),用一組地址任意的存儲單元存放線性表中的數(shù)據(jù)元素。本文將為大家介紹C語言中單鏈表的基本概念與讀取數(shù)據(jù)元素,需要的可以參考一下2021-12-12

