本篇基于上篇红黑树的代码来实现:
【C++】红黑树-CSDN博客
关于map和set可以看:
【C++】map和set的介绍和使用-CSDN博客
改造红黑树
map底层是红黑树的KV模型,set是红黑树的K模型,按理来说,应该设计两种红黑树来模拟实现map和set。但是STL库中并没有这样做,而是复用了同一颗红黑树。
它是如何通过一颗红黑树来模拟实现map和set?
通过第二个模板参数Value来控制节点是pair类型,还是Key类型。
map中传的是pair,Value中节点就是pair类型,set中传的是Key类型,Value中节点就是Key类型。
下面我们来改造自己的红黑树:
节点不再是之前确定的pari类型,而是T类型,具体是什么类型,传给T的是pair就是
pair,传给T的是Key就是Key类型。
但是随之而来就会引发一些问题,在插入的时候就会出问题。
之前是比key小往左边走,比key大往右边走。但是现在节点data的类型并不知道。
如果此时,传给节点data的类型为Key,那么可以直接比较不会有问题,如果传给节点data的类型为pari,可以直接比较吗?
STL库中对于pair的比较是这样实现的:
解释:
first小或者first不小second小,它就小。也就是first和second有一个小就小。
这样的比较方式并不是我们想要的比较。我们想要比较只是比较first,跟second并没有关系。
所以针对map和set要设计两种不同的比较方式。
通过仿函数来设计。
如果KOfT是MapKeyOfT,就去调用map的operator()取出pair中的key,如果KOfT是SetKeyOfT,就去调用set的operator()取出key。
红黑树的迭代器
template<class T>
struct __TreeIterator
{
typedef RBTreeNode<T> Node;
typedef __TreeIterator<T> Self;
Node* _node;
__TreeIterator(Node* node)
:_node(node)
{ }
T& operator*()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
Self& operator++()
{
//
}
Self& operator--()
{
//
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
};
template<class K, class T, class KOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __TreeIterator<T> iterator;
iterator begin()
{
Node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
}
iterator end()
{
return iterator(nullptr);
}
//...
//...
namespace zxa
{
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;
};
void test_map();
}
namespace zxa
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& k)
{
return k;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
bool Insert(const K& k)
{
return _t.Insert(k);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
void test_set();
}
map和set只是对红黑树进行了一层封装 。
const迭代器
通过模板参数简单控制一下即可。
template<class K, class T, class KOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __TreeIterator<T,T&,T*> iterator;
typedef __TreeIterator<T, const T&, const T*> const_iterator;
template<class T,class Ref,class Ptr>
struct __TreeIterator
{
typedef RBTreeNode<T> Node;
typedef __TreeIterator<T,Ref,Ptr> Self;
Node* _node;
__TreeIterator(Node* node)
:_node(node)
{ }
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
operator++
节点5++为节点6,节点6++为节点7,节点7++为节点8,节点8++为节点10。
- 如果_node的右子树不为空,中序遍历的下一个节点就是右子树的最左节点。
- 如果_node的右子树为空,说明_node的子树已经访问完成,下一个节点到它的祖先中找。沿着路径往上,找孩子是它的左的那个祖先。
代码实现:
Self& operator++() { //1.如果右子树不为空,中序的下一个节点就是右子树的最左节点 if (_node->_right) { Node* cur = _node; Node* subLeft = cur->_right; while (subLeft->_left) { subLeft = subLeft->_left; } _node = subLeft; } //2.如果右子树为空,说明_node所在子树已经访问完成,下一个节点到它的祖先中找。 //沿着路径往上找 孩子是它的左的那个祖先 else { Node* cur = _node; Node* parent = cur->_parent; while (parent && parent->_right == cur) { cur = cur->_parent; parent = parent->_parent; } _node = parent; } return *this; }
operator[ ]
map的operator是调用Insert来实现的。
pair<iterator,bool> Insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
operator[]是去找key对应的value。
V& operator[](const K& key)
{
pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
return ret.first->second;
}
关于operator[]的详细分析可以看【C++】map和set的介绍和使用-CSDN博客。
map和set的模拟及测试代码
Myset.hpp
#pragma once
namespace zxa
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& k)
{
return k;
}
};
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& k)
{
return _t.Insert(k);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
void test_set();
}
Mymap.hpp
#pragma once
namespace zxa
{
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 = _t.Insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
void test_map();
}
RBTree.hpp
#pragma once
#include<iostream>
using namespace std;
enum Colour
{
BLACK,
RED,
};
template<class T>
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{ }
};
template<class T,class Ref,class Ptr>
struct __TreeIterator
{
typedef RBTreeNode<T> Node;
typedef __TreeIterator<T,Ref,Ptr> Self;
Node* _node;
__TreeIterator(Node* node)
:_node(node)
{ }
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
//1.如果右子树不为空,中序的下一个节点就是右子树的最左节点
if (_node->_right)
{
Node* cur = _node;
Node* subLeft = cur->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
_node = subLeft;
}
//2.如果右子树为空,说明_node所在子树已经访问完成,下一个节点到它的祖先中找。
//沿着路径往上找 孩子是它的左的那个祖先
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
//...
return *this;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
};
template<class K, class T, class KOfT>
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* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
}
iterator end()
{
return iterator(nullptr);
}
pair<iterator,bool> Insert(const T& data)
{
//按搜索树的方式进行插入
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
//return pair<iterator(_root), true>;
return make_pair(iterator(_root), true);
}
Node* parent = nullptr;
Node* cur = _root;
KOfT koft;
while (cur)
{
if (koft(cur->_data) < koft(data))
{
parent = cur;
cur = cur->_right;
}
else if (koft(cur->_data) > koft(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(iterator(cur), false);
}
}
cur = new Node(data);
Node* newnode = cur;
if (koft(parent->_data) > koft(data))
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//新增节点为红色
cur->_col = RED;
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
{
//情况三:单旋变为情况二
if (cur == parent->_right)
{
RotateL(parent);
swap(parent, cur);
}
//情况二:有可能为情况三变化而来
RotateR(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
break;
}
}
else
{
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->_left)
{
RotateR(parent);
swap(parent, cur);
}
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
break;
}
}
}
//永远把根置为黑
_root->_col = BLACK;
return make_pair(iterator(cur), true);
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
Node* pparent = parent->_parent;
parent->_parent = subR;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
subR->_parent = pparent;
}
}
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
Node* pparent = parent->_parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
}
iterator Find(const K& key)
{
KOfT koft;
Node* cur = _root;
while (cur)
{
if (koft(cur->_data) < data)
{
cur = cur->_right;
}
else if (koft(cur->_data) > data)
{
cur = cur->_left;
}
else
{
return iterator(cur);
}
}
return iterator(nullptr);
}
private:
Node* _root = nullptr;
};
Test.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"RBTree.hpp"
#include"Mymap.hpp"
#include"Myset.hpp"
//查找水果出现的次数
void zxa::test_map()
{
string strs[] = { "西瓜","苹果","西瓜","西瓜","西瓜","西瓜","苹果","樱桃" };
map<string, int> countMap;
//1、如果水果在map中,则operator[]会插入pair<str,0>,返回映射对象(次数)的引用,对它进行++。
//2、如果水果不在map中,则operator[]会返回映射对象(次数)的引用,对它进行++。
for (auto& str : strs)
{
countMap[str]++;
}
for (auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
}
void zxa::test_set()
{
set<int> s;
s.Insert(1);
s.Insert(3);
s.Insert(4);
s.Insert(5);
s.Insert(2);
set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " " << endl;
++it;
}
}
int main()
{
zxa::test_map();
zxa::test_set();
return 0;
}