(1条消息) C++语法(20)---- 模拟红黑树_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130296772?spm=1001.2014.3001.5501
目录
1.stl中的设计思想
2.模拟set和map
1.set和map的类
2.BRTree的仿函数实现
3.红黑树的迭代器
4.set和map迭代器
5.红黑树的insert重新实现
6.map的[]实现
7.set的insert
3.实现代码
1.stl中的设计思想
1.map和set的实现是基于红黑树
2.set中的插入的元素是key,基于查找的元素也是key --- RBTree<K,K>
3.map中的插入的元素是pair<K,V>,基于查找的元素也是key --- RBTree<K,pair<K,V>>
2.模拟set和map
1.set和map的类
set
class Set { public: private: BRTree<K, K> _t; };
map
class Map { public: private: BRTree<K, pair<const K, V>> _t; };
此时两个类的初始构建就有了,但是有一个需要注意的点是,BRTree不知道怎么比较传入的节点,那就不能称之为排序,所以我们需要一个仿函数,接收比较的数据,通过这个数据可以用于比较数据大小。
为什么不用pair自带的比较?因为pair的比较是先比较first的值再比较second的值。但是我们想要其比较的只是Key,所以不符合。
2.BRTree的仿函数实现
template<class K, class T,class KeyOfT> class BRTree { Node* _root = nullptr; };
这个仿函数是返回set或者map比较的元素是什么。
对于set,传入的就是key
template<class K> class Set { public: struct SetKeyOfT { const K& operator()(const K& k) { return k; } private: BRTree<K, K, SetKeyOfT> _t; };
对于map,传入的就是pair的first
template<class K, class V> class Map { public: struct MapKeyOfT { const K& operator()(const pair<K, V>& kv) { return kv.first; } }; private: BRTree<K, pair<const K, V>, MapKeyOfT> _t; };
对于红黑树
用传下来的仿函数,insert调用仿函数传出的节点进行判断数据大小就完成了
3.红黑树的迭代器
其中重要的实现是++和--操作
++操作:如果右边存在,我们要找右树的最小节点(最左节点);如果右边不存在,此时不能返回它的父亲节点,因为访问到右树意味着父亲节点已经被访问了,我们要找到是孩子是父亲的左边的那个祖先
--操作:与++操作很相似,如果左边存在,我们要找左树的最大节点(最右节点);如果左边不存在,此时不能返回它的父亲节点,因为访问到左树意味着父亲节点已经被访问了,我们要找到是孩子是父亲的右边的那个祖先
template <class T, class Ref, class Ptr>
struct __BRTreeIterator
{
typedef BRTreeNode <T> Node;
Node* _node;
typedef __BRTreeIterator<T, Ref, Ptr> Self;
/*-------------------------------------------------------------------------------------------------------*/
typedef __BRTreeIterator<T, T&, T*> iterator;
/*-------------------------------------------------------------------------------------------------------*/
__BRTreeIterator(Node* node)
:_node(node)
{}
/*-------------------------------------------------------------------------------------------------------*/
//普通迭代器时,是拷贝构造
//const迭代器,指出迭代器构造const迭代器
__BRTreeIterator(const iterator& s)
:_node(s._node)
{}
/*-------------------------------------------------------------------------------------------------------*/
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self operator++()
{
if (_node->_right)
{
Node* min = _node->_right;
while (min->_left)
{
min = min->_left;
}
_node = min;
}
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* max = _node->_left;
while (max->_right)
{
max = max->_right;
}
_node = max;
}
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s._node;
}
};
4.set和map迭代器
set
注意:设计set时,它的迭代器不能修改里面的内容,因为搜索二叉树的结构可能会被破坏
因此set的普通迭代器和const迭代器都是红黑树的const迭代器构造的。
因此begin和end实现时,需要把this指针变为const型,不然传入会被权限放大
typedef typename BRTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename BRTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const
{
return _t.begin();
}
iterator end() const
{
return _t.end();
}
map
注意:设计map时,它的迭代器需要修改里面的内容,多少也不能破坏搜索二叉树的结构
所以我们传入的pair中key是const类型,这样就保证key不能被修改
那么迭代器就可以有普通和const型
typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
const_iterator begin() const
{
return _t.begin();
}
const_iterator end() const
{
return _t.end();
}
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
5.红黑树的insert重新实现
stl中的红黑树实现了[]来统计次数,[]调用的是insert,而insert函数的返回值是一个pair类型。pair存储两个东西,一个是迭代器,一个是bool类型的数。insert插入成功,返回插入的新迭代器位置,bool类型为true;insert插入失败返回的迭代器是找到对应数的迭代器,bool是false
pair<iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = Black;
return make_pair(iterator(_root), true);
}
KeyOfT kot;
//父子节点确定插入的位置
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) > kot(data))
{
parent = cur;
cur = cur->_left;
}
else if (kot(cur->_data) < kot(data))
{
parent = cur;
cur = cur->_right;
}
else
return make_pair(iterator(cur), false);
}
//走到这cur就是要插入的位置
//cur要连接parent,parent也要连接cur---判断靠kv的大小
cur = new Node(data);
Node* newnode = cur;
if (kot(parent->_data) > kot(cur->_data))
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
while (parent && parent->_col == Red)
{
Node* grandparent = parent->_parent;
//parent分在grandparent左右
if (grandparent->_left == parent)
{
//关键是看uncle节点不存在/红色/黑色的情况
Node* uncle = grandparent->_right;
//1.uncle红
//parent和uncle变黑,grandparent变红
//grandparent变红需要往上判断
if (uncle && uncle->_col == Red)
{
grandparent->_col = Red;
parent->_col = uncle->_col = Black;
cur = grandparent;
parent = cur->_parent;
}
else //uncle不存在/黑色
{
//2.cur也是parent的左边,uncle不存在/黑色
//右旋grandparents,parent变黑,
if (cur == parent->_left)
{
_RotateR(grandparent);
parent->_col = Black;
grandparent->_col = Red;
}
//3.cur是parent的右边,uncle不存在/黑色
//左旋parent再右旋grandparents,cur变黑,grandparents变红
else
{
_RotateL(parent);
_RotateR(grandparent);
cur->_col = Black;
grandparent->_col = Red;
}
//抽象树的头被设置为黑色,对上面没有影响,所以不需要进行循环
break;
}
}
else
{
Node* uncle = grandparent->_left;
//1.uncle红
//parent和uncle变黑,grandparent变红
//grandparent变红需要往上判断
if (uncle && uncle->_col == Red)
{
grandparent->_col = Red;
parent->_col = uncle->_col = Black;
cur = grandparent;
parent = cur->_parent;
}
else //uncle不存在/黑色
{
//2.cur也是parent的右边,uncle不存在/黑色
//左旋grandparents,parent变黑,
if (cur == parent->_right)
{
_RotateL(grandparent);
parent->_col = Black;
grandparent->_col = Red;
}
//3.cur是parent的右边,uncle不存在/黑色
//右旋parent再左旋grandparents,cur变黑,grandparents变红
else
{
_RotateR(parent);
_RotateL(grandparent);
cur->_col = Black;
grandparent->_col = Red;
}
//抽象树的头被设置为黑色,对上面没有影响,所以不需要进行循环
break;
}
}
}
_root->_col = Black;
return make_pair(iterator(newnode), true);
}
6.map的[]实现
如果成功返回新迭代器位置
失败返回找到的迭代器位置
V& operator[](const K& k)
{
pair<iterator, bool> ret = Insert(make_pair(k, V()));
return ret.first->second;
}
pair<iterator, bool> Insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
7.set的insert
set的普通迭代器是红黑树的const迭代器重命名的,但是insert调用的是红黑树的普通迭代器,如果直接insert红黑树的,普通迭代器和const迭代器类型是无法相互转换。所以我们需要调用红黑树原生普通迭代器。
不过,在stl中都实现了普通迭代器与const迭代器的转换
实现的思路就是:
1.在迭代器实现时重命名两个迭代器,一个是<T,R,P>,一个是<T,T*,T&>
2.在类中的普通迭代器,那么这两个都是一样的,是普通迭代器
3.在类中传入const的数据,那么左边是const迭代器,右边是普通迭代器
4.在迭代器的构造中,实现两个构造函数
pair<iterator, bool> Insert(const K& k)
{
pair<typename BRTree<K, K, SetKeyOfT>::iterator, bool>ret = _t.Insert(k);
//1.取红黑树里的普通迭代器,因为set的迭代器都是const变过来的
//2.类模板中分不清是迭代器还是成员函数,所以需要变成typename
return pair<iterator, bool>(ret.first, ret.second);
//普通迭代器可以构造成const迭代器,所以需要调用红黑树的const迭代器构造
}
3.实现代码
RBTrss.hpp
#pragma once #include<iostream> #include<assert.h> #include <stdlib.h> #include<time.h> using namespace std; using namespace std; enum Color { Black, Red, }; template <class T> struct BRTreeNode { T _data; BRTreeNode<T>* _left; BRTreeNode<T>* _right; BRTreeNode<T>* _parent; Color _col; BRTreeNode(const T& data) :_data(data) , _left(nullptr) , _right(nullptr) , _parent(nullptr) , _col(Red) {} }; template <class T, class Ref, class Ptr> struct __BRTreeIterator { typedef BRTreeNode <T> Node; Node* _node; typedef __BRTreeIterator<T, Ref, Ptr> Self; /*-------------------------------------------------------------------------------------------------------*/ typedef __BRTreeIterator<T, T&, T*> iterator; /*-------------------------------------------------------------------------------------------------------*/ __BRTreeIterator(Node* node) :_node(node) {} /*-------------------------------------------------------------------------------------------------------*/ //普通迭代器时,是拷贝构造 //const迭代器,指出迭代器构造const迭代器 __BRTreeIterator(const iterator& s) :_node(s._node) {} /*-------------------------------------------------------------------------------------------------------*/ Ref operator*() { return _node->_data; } Ptr operator->() { return &_node->_data; } Self operator++() { if (_node->_right) { Node* min = _node->_right; while (min->_left) { min = min->_left; } _node = min; } 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* max = _node->_left; while (max->_right) { max = max->_right; } _node = max; } else { Node* cur = _node; Node* parent = cur->_parent; while (parent && cur == parent->_left) { cur = parent; parent = parent->_parent; } _node = parent; } return *this; } bool operator!=(const Self& s) const { return _node != s._node; } bool operator==(const Self& s) const { return _node == s._node; } }; /*-------------------------------------------------------------------------------------------------------*/ template<class K, class T,class KeyOfT> class BRTree { public: typedef BRTreeNode<T> Node; typedef __BRTreeIterator<T, T&, T*> iterator; typedef __BRTreeIterator<T,const T&,const T*> const_iterator; iterator begin() { Node* left = _root; while (left && left->_left) { left = left->_left; } return iterator(left); } iterator end() { return iterator(nullptr); } const_iterator begin() const { Node* left = _root; while (left && left->_left) { left = left->_left; } return const_iterator(left); } const_iterator end() const { return const_iterator(nullptr); } pair<iterator, bool> Insert(const T& data) { if (_root == nullptr) { _root = new Node(data); _root->_col = Black; return make_pair(iterator(_root), true); } KeyOfT kot; //父子节点确定插入的位置 Node* parent = nullptr; Node* cur = _root; while (cur) { if (kot(cur->_data) > kot(data)) { parent = cur; cur = cur->_left; } else if (kot(cur->_data) < kot(data)) { parent = cur; cur = cur->_right; } else return make_pair(iterator(cur), false); } //走到这cur就是要插入的位置 //cur要连接parent,parent也要连接cur---判断靠kv的大小 cur = new Node(data); Node* newnode = cur; if (kot(parent->_data) > kot(cur->_data)) { parent->_left = cur; cur->_parent = parent; } else { parent->_right = cur; cur->_parent = parent; } while (parent && parent->_col == Red) { Node* grandparent = parent->_parent; //parent分在grandparent左右 if (grandparent->_left == parent) { //关键是看uncle节点不存在/红色/黑色的情况 Node* uncle = grandparent->_right; //1.uncle红 //parent和uncle变黑,grandparent变红 //grandparent变红需要往上判断 if (uncle && uncle->_col == Red) { grandparent->_col = Red; parent->_col = uncle->_col = Black; cur = grandparent; parent = cur->_parent; } else //uncle不存在/黑色 { //2.cur也是parent的左边,uncle不存在/黑色 //右旋grandparents,parent变黑, if (cur == parent->_left) { _RotateR(grandparent); parent->_col = Black; grandparent->_col = Red; } //3.cur是parent的右边,uncle不存在/黑色 //左旋parent再右旋grandparents,cur变黑,grandparents变红 else { _RotateL(parent); _RotateR(grandparent); cur->_col = Black; grandparent->_col = Red; } //抽象树的头被设置为黑色,对上面没有影响,所以不需要进行循环 break; } } else { Node* uncle = grandparent->_left; //1.uncle红 //parent和uncle变黑,grandparent变红 //grandparent变红需要往上判断 if (uncle && uncle->_col == Red) { grandparent->_col = Red; parent->_col = uncle->_col = Black; cur = grandparent; parent = cur->_parent; } else //uncle不存在/黑色 { //2.cur也是parent的右边,uncle不存在/黑色 //左旋grandparents,parent变黑, if (cur == parent->_right) { _RotateL(grandparent); parent->_col = Black; grandparent->_col = Red; } //3.cur是parent的右边,uncle不存在/黑色 //右旋parent再左旋grandparents,cur变黑,grandparents变红 else { _RotateR(parent); _RotateL(grandparent); cur->_col = Black; grandparent->_col = Red; } //抽象树的头被设置为黑色,对上面没有影响,所以不需要进行循环 break; } } } _root->_col = Black; return make_pair(iterator(newnode), true); } void Print() { _Print(_root); cout << endl; } bool Inspect() { return _Inspect(_root); } private: bool _Find(Node* root, const T& data) { if (root == nullptr) return false; if (root->_data == data) return true; return _Find(root->_left) || _Find(root->_right); } bool check(Node* root, size_t& reference, size_t num) { if (root == nullptr) { if (num != reference) { cout << "路径长度有问题" << endl; return false; } return true; } if (root->_col == Red && root->_parent && root->_parent->_col == Red) { cout << "节点连续红色" << endl; return false; } if (root->_col == Black) num++; return check(root->_left, reference, num) && check(root->_right, reference, num); } bool _Inspect(Node* root) { //空树也是红黑树 if (_root == nullptr) return true; //检测根节点是否为黑色 if (_root->_col != Black) { cout << "根节点是红色的" << endl; return false; } size_t leftNum = 0; Node* cur = _root; while (cur) { if (cur->_col == Black) leftNum++; cur = cur->_left; } //检测所有路径黑色节点的数量是否一样 //检测相邻节点是不是都是红色的 return check(_root, leftNum, 0); } void _Print(Node*& cur) { if (cur == nullptr) return; _Print(cur->_left); cout << cur->_kv.first << " "; _Print(cur->_right); } void _RotateL(Node*& parent) { Node* pparent = parent->_parent; Node* SubR = parent->_right; Node* SubRL = SubR->_left; if (pparent == nullptr) { _root = SubR; SubR->_parent = nullptr; } else { if (pparent->_left == parent) pparent->_left = SubR; else pparent->_right = SubR; SubR->_parent = pparent; } parent->_parent = SubR; SubR->_left = parent; parent->_right = SubRL; if (SubRL != nullptr) SubRL->_parent = parent; } void _RotateR(Node*& parent) { Node* pparent = parent->_parent; Node* SubL = parent->_left; Node* SubLR = SubL->_right; if (pparent == nullptr) { _root = SubL; SubL->_parent = nullptr; } else { if (pparent->_left == parent) pparent->_left = SubL; else pparent->_right = SubL; SubL->_parent = pparent; } parent->_parent = SubL; SubL->_right = parent; parent->_left = SubLR; if (SubLR != nullptr) SubLR->_parent = parent; } Node* _root = nullptr; };
map.cc
#pragma once #include "BRTree.h" #include <map> namespace MY { template<class K, class V> class Map { public: struct MapKeyOfT { const K& operator()(const pair<K, V>& kv) { return kv.first; } }; V& operator[](const K& k) { pair<iterator, bool> ret = Insert(make_pair(k, V())); return ret.first->second; } typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator; typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator; pair<iterator, bool> Insert(const pair<K, V>& kv) { return _t.Insert(kv); } const_iterator begin() const { return _t.begin(); } const_iterator end() const { return _t.end(); } iterator begin() { return _t.begin(); } iterator end() { return _t.end(); } private: BRTree<K, pair<const K, V>, MapKeyOfT> _t; }; void MapText() { Map<int, int> m; //int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 }; //int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 }; int arr[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7 }; for (int e : arr) { m.Insert(make_pair(e, e)); } Map<int, int>::iterator it = m.begin(); while (it != m.end()) { cout << it->first << ":" << it->second << " "; ++it; } cout << endl; } }
set.cc
#pragma once #include "BRTree.h" namespace MY{ template<class K> class Set { public: struct SetKeyOfT { const K& operator()(const K& k) { return k; } bool Insert(const K& k) { return _t.Insert(k); } }; typedef typename BRTree<K, K, SetKeyOfT>::const_iterator iterator; typedef typename BRTree<K, K, SetKeyOfT>::const_iterator const_iterator; pair<iterator, bool> Insert(const K& k) { pair<typename BRTree<K, K, SetKeyOfT>::iterator, bool>ret = _t.Insert(k); //1.取红黑树里的普通迭代器,因为set的迭代器都是const变过来的 //2.类模板中分不清是迭代器还是成员函数,所以需要变成typename return pair<iterator, bool>(ret.first, ret.second); //普通迭代器可以构造成const迭代器,所以需要调用红黑树的const迭代器构造 } iterator begin() const { return _t.begin(); } iterator end() const { return _t.end(); } const_iterator begin() const { return _t.begin(); } const_iterator end() const { return _t.end(); } private: BRTree<K, K, SetKeyOfT> _t; }; void SetText() { Set<int> s; //int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 }; //int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 }; int arr[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7 }; for (int e : arr) { s.Insert(e); } Set<int>::iterator it = s.begin(); while (it != s.end()) { cout << *it << " "; ++it; } } }