目录
前言
在前面简单实现的红黑树,实际大家发现是写死的,也就是里面的数据类型是pair,它确实可以封装成map,但是set呢?而实际上set和map底层实现逻辑大差不差,没有必要写重复的两份代码,所以这时就可以采用模板和泛型编程就能解决这样的问题。那么我们就需要来改造改造已有的红黑树了。这里为了方便,先给出原来实现的KV模型的红黑树。
#include <iostream>
using namespace std;
//枚举颜色
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Color _co;
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _co(RED)
{}
};
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->_co = BLACK;//根结点一定为黑
return true;
}
//找位置插入
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
cur->_co = RED;//新增结点一定为红色
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//插入后,开始调色
//分情况调色
while (parent && parent->_co == RED)//调到黑色或者空就停止
{
Node* g = parent->_parent;
if (parent == g->_left)//父亲在左,叔叔在右
{
Node* u = g->_right;
//情况一:叔叔存在且为红,叔叔和父亲变红,爷爷g变黑
if (u && u->_co == RED)
{
parent->_co = u->_co = BLACK;
g->_co = RED;
//向上调整
cur = g;
parent = cur->_parent;
}
else//叔叔不存在或者存在且为黑
{
// g
// p u
// c
//右单旋,p变黑,g变红
if (cur == parent->_left)
{
RotaRTree(g);
parent->_co = BLACK;
g->_co = RED;
}
// g
// p u
// c
//左右双旋,先左再右。cur就变成了p的父亲
else
{
RotaLTree(parent);//左单旋
RotaRTree(g);//右单旋
cur->_co = BLACK;
g->_co = RED;
}
//不需要再调整,直接结束
break;
}
}
else//父亲在右,叔叔在左
{
Node* u = g->_left;
if (u && u->_co == RED)//u存在且为红
{
parent->_co = u->_co = BLACK;
g->_co = RED;
cur = g;
parent = cur->_parent;
}
else//叔叔不存在或者为黑
{
// g
// u p
// c
//左单旋,p变黑,g变红
if (cur == parent->_right)
{
parent->_co = BLACK;
g->_co = RED;
RotaLTree(g);
}
// g
// u p
// c
//右左双旋,先右旋,在左旋
else
{
RotaRTree(parent);//右
RotaLTree(g);//左
cur->_co = BLACK;
g->_co = RED;
}
break;
}
}
}
_root->_co = BLACK;//始终保持根是黑色
return true;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
//根为红就错误
if (_root->_co == RED)
{
cout << "不符合根结点为黑这一规则" << endl;
return false;
}
//先以一条路径为标志位,每条路径上的黑色结点的数和该标志位相比,不一样就不满足规则四
int refnum = 0;//基准位
Node* cur = _root;
while (cur)
{
if (cur->_co == BLACK)
refnum++;
cur = cur->_left;
}
return _IsBalance(_root, 0, refnum);
}
private:
Node* _root = nullptr;
bool _IsBalance(Node* root, int curblacknum, const int refnum)
{
if (root == nullptr)
{
if (curblacknum != refnum)
{
cout << "存在黑色结点不同的路径" << endl;
return false;
}
return true;
}
if (root->_co == RED && root->_parent->_co == RED)
{
cout << "存在连续两个红色结点" << endl;
return false;
}
if (root->_co == BLACK)
{
++curblacknum;
}
return _IsBalance(root->_left, curblacknum, refnum) && _IsBalance(root->_right, curblacknum, refnum);
}
//右旋
void RotaRTree(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* pparent = parent->_parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (parent == pparent->_left)
pparent->_left = subL;
else
pparent->_right = subL;
subL->_parent = pparent;
}
}
//左旋
void RotaLTree(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* pparent = parent->_parent;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (parent == pparent->_left)
pparent->_left = subR;
else
pparent->_right = subR;
subR->_parent = pparent;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << " ";
_InOrder(root->_right);
}
};
一、改造红黑树(重点)
改造结点类
对于map容器,每一个元素是pair键值对,KV模型;对于set容器,每一个元素就是一个值value,但底层是<value,value>,K模型,所以为了能够很好的兼容两者,这里的结点直接采用模板参数T来表示,T会根据传入的类型进行实例化,传入Key就是Key,传入pair就是pair。实现如下
//T可能是key,也可能是pair<K,V>
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _co;
RBTreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_co(RED)
{}
};
改造主体
参数改造
这里的红黑树模板参数有三个:
template<class K,class T,class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
private:
Node* _root = nullptr;
};
前两个参数好理解,原来KV,改成KT,这个T是为了好区分。。可能有人会有疑问能不能把红黑树的第一个模板参数去掉?不能的,因为像find这样的接口需要用Key。第三个模板参数主要是为了比较大小。
仿函数的增加
第三个参数KeyOfT实际上用的仿函数,为何?因为所有比较大小的方式需要改变,因为用的同一棵红黑树,那就要兼容。原来插入是pair,但比较大小比的是Key,对于pair来说,取Key就是取first,可是set中并没有first,那怎么取?这就是这个仿函数的作用,根据上层map、set传入的仿函数,取出各自的键值Key比较。如下:
- set中的仿函数
template<class K>
class set
{
struct SetKey
{
const K& operator()(const K& key)
{
return key;
}
};
//……
private:
RBTree<K, K, SetKey> _s;
};
- map的仿函数
template<class K,class V>
class map
{
//内部类
struct MapKey
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
//……
private:
RBTree<K, pair<K, V>, MapKey> _m;
};
红黑树的插入
pair<Iterator,bool> Insert(const T& date)
{
if (_root == nullptr)
{
_root = new Node(date);
_root->_co = BLACK;
return make_pair(Iterator(_root),true);
}
KeyOfT kot;//kot对象
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
//k
//pair<K,V>
//kot对象,用来取T类型的data里面的Key
if (kot(date) > 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->_co = RED;//新增结点一定为红色
if (kot(date) > kot(parent->_data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//插入后,开始调色
//分情况调色
//………………………………
所有的比较逻辑都要改变哦!!
正向迭代器实现
这里的迭代器就是和在list模拟实现时的类似,底层就是结点的指针,但因为是树,++/--等操作都不能遍历到下一个结点,所以得封装成自定义类型。
//正向迭代器结构
template<class T, class Ref,class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, T&, T*> Self;
Node* _node;
__RBTreeIterator(Node* node)
:_node(node)
{}
};
迭代器实现的难点在于:如何进行++/--操作?
++操作:
实际上离不开中序遍历的规则,左->根->右,也就是主要看右子树的情况,因为遍历完右子树说明这一轮的遍历已经完成了,接下就是找下一个结点。。即左子树。。情况如下:
- 右子树不为空,下一个结点就是右子树的最左结点
- 右子树为空,倒着找一个满足以当前结点作为左子树的祖先结点,它就是下一个遍历结点
Self& operator++()
{
//右子树存在,下一个遍历的是右子树最左侧的结点
if (_node->_right)
{
Node* leftMin = _node->_right;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
_node = leftMin;
}
//右子树不存在,倒着回去找到以当前结点作为左孩子的那个结点
else
{
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)
{
Node* rightMin = _node->_left;
while (rightMin && rightMin->_right)
{
rightMin = rightMin->_right;
}
_node = rightMin;
}
//左子树不存在,倒着回去找到以当前结点作为右孩子的那个结点,即cur!=parent->left
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
反向迭代器实现
实现起来也很容易,实际就是对正向迭代器的封装,是一种适配器模式。这里直接给代码
//反向迭代器
template<class Iterator,class Ref,class Ptr>
struct _ReverIterator
{
typedef _ReverIterator<Iterator,Ref,Ptr> Self;
Iterator _it;
_ReverIterator(Iterator it)
:_it(it)
{}
Ref operator*()
{
return *_it;
}
Ptr operator->()
{
return _it.operator->();
}
bool operator!=(const Self& s)
{
return _it!=s._it;
}
bool operator==(const Self& s)
{
return _it==s._it;
}
//前置++
Self& operator++()
{
--_it;
return *this;
}
//前置--
Self& operator--()
{
++_it;
return *this;
}
};
这里没有实现const迭代器,因为逻辑和非const一样一样的 ,只需在类型前面加上const,对于函数名后加上const即可。
typedef __RBTreeIterator<const T, const T&, const T*> ConstIterator;
ConstIterator Begin()const
{
Node* leftMin = _root;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
return ConstIterator(leftMin);
}
ConstIterator End()const
{
return ConstIterator(nullptr);
}
改造后的红黑树完整
#pragma once
#include <iostream>
using namespace std;
enum Color
{
RED,
BLACK
};
//T可能是key,也可能是pair<K,V>
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _co;
RBTreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_co(RED)
{}
};
//反向迭代器
template<class Iterator,class Ref,class Ptr>
struct _ReverIterator
{
typedef _ReverIterator<Iterator,Ref,Ptr> Self;
Iterator _it;
_ReverIterator(Iterator it)
:_it(it)
{}
Ref operator*()
{
return *_it;
}
Ptr operator->()
{
return _it.operator->();
}
bool operator!=(const Self& s)
{
return _it!=s._it;
}
bool operator==(const Self& s)
{
return _it==s._it;
}
//前置++
Self& operator++()
{
--_it;
return *this;
}
//前置--
Self& operator--()
{
++_it;
return *this;
}
};
//正向迭代器
template<class T, class Ref,class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, T&, T*> Self;
Node* _node;
__RBTreeIterator(Node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
//前置++
Self& operator++()
{
//右子树存在,下一个遍历的是最左侧的结点
if (_node->_right)
{
Node* leftMin = _node->_right;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
_node = leftMin;
}
//右子树不存在,倒着回去找到以当前结点作为左孩子的那个结点
else
{
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)
{
Node* rightMin = _node->_left;
while (rightMin && rightMin->_right)
{
rightMin = rightMin->_right;
}
_node = rightMin;
}
//左子树不存在,倒着回去找到以当前结点作为右孩子的那个结点,即cur!=parent->left
else
{
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
{
typedef RBTreeNode<T> Node;
public:
typedef __RBTreeIterator<T, T&, T*> Iterator;
typedef _ReverIterator<Iterator,T&,T*> ReverIterator;
RBTree() = default;//强制生成默认构造
//拷贝构造,前序遍历
RBTree(const RBTree<K, T, KeyOfT>& r)
{
_root = Copy(r._root);
}
Node* Copy(Node* root)
{
if (root == nullptr)
return nullptr;
Node* newroot = new Node(root->_data);
newroot->_co = root->_co;
newroot->_left = Copy(root->_left);
if (newroot->left)
newroot->_left->_parent = newroot;
newroot->_right = Copy(root->_right);
if (newroot->_right)
newroot->_right->_parent = newroot;
return newroot;
}
//t2=t1
//现代写法
RBTree<K, T,KeyOfT>& operator=(RBTree<K, T, KeyOfT> r)
{
swap(_root, r._root);
return *this;
}
//析构函数
~RBTree()
{
Destroy(_root);
_root = nullptr;
}
void Destroy(Node* root)
{
if (root == nullptr)
return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
Iterator Begin()
{
Node* leftMin = _root;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
return Iterator(leftMin);
}
Iterator End()
{
return Iterator(nullptr);
}
ReverIterator RBegin()
{
Node* rightMin = _root;
while (rightMin && rightMin->_right)
{
rightMin = rightMin->_right;
}
return ReverIterator(Iterator(rightMin));
}
ReverIterator REnd()
{
return ReverIterator(nullptr);
}
pair<Iterator,bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_co = BLACK;//根结点一定为黑
return make_pair(Iterator(_root),true);
}
KeyOfT kot;//对象
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
//k
//pair<K,V>
//kot对象,用来取T类型的data里面的Key
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->_co = RED;//新增结点一定为红色
if (kot(data) > kot(parent->_data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//插入后,开始调色
//分情况调色
while (parent && parent->_co == RED)//调到黑色或者空就停止
{
Node* g = parent->_parent;
if (parent == g->_left)//父亲在左,叔叔在右
{
Node* u = g->_right;
//情况一:叔叔存在且为红,叔叔和父亲变红,爷爷g变黑
if (u && u->_co == RED)
{
parent->_co = u->_co = BLACK;
g->_co = RED;
//向上调整
cur = g;
parent = cur->_parent;
}
else//叔叔不存在或者存在且为黑
{
// g
// p u
// c
//右单旋,p变黑,g变红
if (cur == parent->_left)
{
RotaRTree(g);
parent->_co = BLACK;
g->_co = RED;
}
// g
// p u
// c
//左右双旋,先左再右。cur就变成了p的父亲
else
{
RotaLTree(parent);//左单旋
RotaRTree(g);//右单旋
cur->_co = BLACK;
g->_co = RED;
}
//不需要再调整,直接结束
break;
}
}
else//父亲在右,叔叔在左
{
Node* u = g->_left;
if (u && u->_co == RED)//u存在且为红
{
parent->_co = u->_co = BLACK;
g->_co = RED;
cur = g;
parent = cur->_parent;
}
else//叔叔不存在或者为黑
{
// g
// u p
// c
//左单旋,p变黑,g变红
if (cur == parent->_right)
{
parent->_co = BLACK;
g->_co = RED;
RotaLTree(g);
}
// g
// u p
// c
//右左双旋,先右旋,在左旋
else
{
RotaRTree(parent);//右
RotaLTree(g);//左
cur->_co = BLACK;
g->_co = RED;
}
break;
}
}
}
_root->_co = BLACK;//始终保持根是黑色
return make_pair(Iterator(newNode), true);
}
Iterator Find(const K& key)
{
Node* cur = _root;
KeyOfT kot;
while (cur)
{
if ((key) < kot(cur->_data))
cur = cur->_left;
else if (key > kot(cur->_data))
cur = cur->_right;
else
return Iterator(cur);
}
return nullptr;
}
private:
Node* _root = nullptr;
//右旋
void RotaRTree(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* pparent = parent->_parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (parent == pparent->_left)
pparent->_left = subL;
else
pparent->_right = subL;
subL->_parent = pparent;
}
}
//左旋
void RotaLTree(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* pparent = parent->_parent;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (parent == pparent->_left)
pparent->_left = subR;
else
pparent->_right = subR;
subR->_parent = pparent;
}
}
};
二、map模拟实现
说过底层就是一棵红黑树,所以成员变量就是使用改造后的红黑树进行封装而已咯,没啥的。基本都是调用红黑树的接口。从侧面体现了封装的特性与其强大之处
namespace Ma//模拟实现要在自己的命名空间
{
template<class K,class V>
class map
{
//内部类
struct MapKey
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
typedef typename RBTree<K, pair<const K, V>, MapKey>::Iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKey>::ReverIterator rever_iterator;
public:
iterator begin()
{
return _m.Begin();
}
iterator end()
{
return _m.End();
}
rever_iterator rbegin()
{
return _m.RBegin();
}
rever_iterator rend()
{
return _m.REnd();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _m.Insert(kv);
}
iterator find(const K& key)
{
return _m.Find();
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = _m.Insert(make_pair(key, V()));
iterator it = ret.first;
return it->second;
}
private:
RBTree<K, pair<const K, V>, MapKey> _m;
};
三、set模拟实现
同样也是红黑树的封装。。。
namespace Se
{
template<class K>
class set
{
struct SetKey
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename RBTree<K, const K, SetKey>::Iterator iterator;
typedef typename RBTree<K, const K, SetKey>::ReverIterator rever_iterator;
public:
iterator begin()
{
return _s.Begin();
}
iterator end()
{
return _s.End();
}
rever_iterator rbegin()
{
return _s.RBegin();
}
rever_iterator rend()
{
return _s.REnd();
}
pair<iterator, bool> insert(const K& value)
{
return _s.Insert(value);
}
iterator find(const K& key)
{
return _s.Find();
}
private:
RBTree<K, const K, SetKey> _s;
};
这里说明一下这段代码:
typedef typename RBTree<K, const K, SetKey>::Iterator iterator;
typedef typename RBTree<K, const K, SetKey>::ReverIterator rever_iterator;
typename实际上在模板时有讲过它可以声明模板参数 也就是可以和class替换。但在此处便是它的第二个用处声明嵌套从属名称,如
//嵌套从属名称
RBTree<K, const K, SetKey>::Iterator
对于这样的情况必须加上typename关键字修饰,否则会报错!!因为使用了模板参数K。在K被编译器具现化之前,是不知道它是什么类型的,也就是无法得知RBTree<K, const K, SetKey>里面的Iterator究竟是什么东西,是类型?函数?其他?编译器是不知道的,加上typename可以告诉编译器它是一个类型!
以上只是简单模拟实现,不是说和库里面完全一样,要是小编能完全和库一样,我直接起飞!重点在体会封装,模板的强大之处。。
今天的分享就到这,如果你有收获,欢迎三连!!