当前位置: 首页 > news >正文

基于红黑树的插入功能,对Set和Map部分功能进行封装实现

一、红黑树的迭代器

        在上一篇中,对红黑树的插入功能进行了实现,但是要封装出set和map,还需要实现出红黑树的迭代器。

        红黑树的迭代器本质上还是红黑树树结点的指针,但是需要实现一些符号重载:

template<class T, class ref, class ptr>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, ref, ptr> Self;Node* _node = nullptr;RBTreeIterator(Node* node):_node(node){}Self& operator++() {if (_node->_right != nullptr) {_node = _node->_right;while (_node->_left != nullptr) {_node = _node->_left;}return *this;}else {Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_right) {cur = parent;parent = cur->_parent;}_node = parent;return *this;}}ref operator*() {return _node->_data;}ptr operator->() {return &(_node->_data);}bool operator!=(const Self& s)const {return s._node != _node;}bool operator==(const Self& s)const {return s._node == _node;}
};

 1.1 operator++的重载

        由于红黑树 本质上还是搜索二叉树,迭代器在移动时,是按照中序遍历的顺序进行移动,以便于在进行范围for等操作时,有序输出。

        因此,++操作,我们需要知道的就是,一个结点在中序遍历的情况下,下一个结点该如何寻找。

        我们以4结点为例子,假如要对4进行++,下一个结点应该是5,而5与4的关系就是,5是4结点右子树中最左的结点,因此,如果一个结点有右子树,就去找右子树最左的结点。

        那么再看5,5的下一个结点应该是6,按照第一步来判断,5结点右子树为空,因此需要向上查找,6是5的父结点,那么就直接找父结点吗?

        再来看看3结点,3结点的下一个结点是4,并不是3结点的父结点。这又有什么规律呢?其实与结点和父结点之间的位置决定。

        由于中序遍历是左根右,如果3结点被访问,3结点又是2结点的右子树,说明2结点以及之前的结点一定被访问过了。

        因此,当右子树不存在时,需要向上寻找,直到找到子树是父结点的左子树的父结点,例如:5是6的左子树,那么下一个结点就是6结点。

1.2 const_iterator的实现

        红黑树的const_iterator与list的实现相同,通过增加两个模板参数,封装出两个不同版本的iterator,即:

        如果传过来的模板参数是<T, T&, T*>那么就是普通的iterator,如果传过来的是<T, const T&, const T*>那么就是const_iterator。

二、对红黑树进行修改

        由于set与map的数据类型不一样,如果说set的数据类型是T,那么map的数据类型就是pair<K, T>,如果不是按照上一篇中的K,V结构红黑树来进行封装,在读取map的数据进行插入时,就会出现问题,因为pair的大小比较,不仅会涉及到K,还会涉及到T。因此,对红黑树进行修改,同时,也在map和set中增加一个伪函数,传入红黑树中,用来读取插入数据中的K,从而进行比较:

template<class K, class T, class KOT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef RBTreeIterator<T, T&, T*> iterator;typedef RBTreeIterator<T, const T&, const T*> const_iterator;iterator begin() {Node* tmp = _root;while (tmp->_left != nullptr) {tmp = tmp->_left;}return tmp;}iterator end() {return nullptr;}const_iterator begin() const{if (_root == nullptr) return nullptr;Node* tmp = _root;while (tmp->_left != nullptr) {tmp = tmp->_left;}return tmp;}const_iterator end() const{return nullptr;}~RBTree(){Destroy(_root);_root = nullptr;}void clear() {Destroy(_root);_root = nullptr;}iterator find(const K& key) {Node* tmp = _root;KOT kot;while (tmp) {if (kot(tmp->_data) < key) {tmp = tmp->_right;}else if (kot(tmp->_data) > key) {tmp = tmp->_left;}else {return tmp;}}return nullptr;}pair<Node*, bool> Insert(const T& kv) {if (_root == nullptr) {_root = new Node(kv);_root->_col = BLACK;return make_pair(_root, true);}Node* cur = _root;Node* parent = nullptr;KOT kot;while (cur) {parent = cur;if (kot(cur->_data) < kot(kv)) {cur = cur->_right;}else if (kot(cur->_data) > kot(kv)) {cur = cur->_left;}else {return make_pair(cur, false);}}cur = new Node(kv);cur->_parent = parent;if (kot(parent->_data) > kot(kv)) {parent->_left = cur;}else {parent->_right = cur;}if (parent->_col == BLACK) {return make_pair(cur,true);}Node* pp = parent->_parent;while (parent && pp) {Node* uncle = nullptr;if (parent == pp->_left) {uncle = pp->_right;}else {uncle = pp->_left;}if (uncle != nullptr && uncle->_col == RED) {parent->_col = BLACK;pp->_col = RED;uncle->_col = BLACK;cur = pp;if (cur->_parent == nullptr) {cur->_col = BLACK;return make_pair(cur,true);}if (cur->_parent->_col == BLACK) return make_pair(cur,true);parent = cur->_parent;pp = parent->_parent;}else {if (parent == pp->_left && cur == parent->_left) {RotateR(pp);parent->_col = BLACK;pp->_col = RED;}else if (parent == pp->_left && cur == parent->_right) {RotateLR(pp);cur->_col = BLACK;pp->_col = RED;}else if (parent == pp->_right && cur == parent->_left) {RotateRL(pp);cur->_col = BLACK;pp->_col = RED;}else {RotateL(pp);parent->_col = BLACK;pp->_col = RED;}break;}}while (parent != nullptr && parent->_parent != nullptr) {parent = parent->_parent;}_root = parent;return make_pair(cur,true);}bool IsBalanceTree(){if (_root == nullptr)return true;if (_root->_col == RED)return false;// 参考值int refNum = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){++refNum;}cur = cur->_left;}return Check(_root, 0, refNum);}void InOrder() {_InOrder(_root);}private:void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}// 前序递归遍历bool Check(Node* root, int blackNum, const int refNum){if (root == nullptr){// 前序遍历走到空时,意味着一条路径走完了//cout << blackNum << endl;if (refNum != blackNum){cout << "存在黑色结点的数量不相等的路径" << endl;return false;}return true;}// 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了if (root->_col == RED && root->_parent && root->_parent->_col == RED){cout << root->_kv.first << "存在连续的红色结点" << endl;return false;}if (root->_col == BLACK){blackNum++;}return Check(root->_left, blackNum, refNum)&& Check(root->_right, blackNum, refNum);}// 右单旋void RotateR(Node* pParent) {Node* cur = pParent->_left;pParent->_left = cur->_right;cur->_right = pParent;if (pParent->_left != nullptr) {pParent->_left->_parent = pParent;}cur->_parent = pParent->_parent;pParent->_parent = cur;if (cur->_parent != nullptr) {if (cur->_parent->_left == pParent) {cur->_parent->_left = cur;}else {cur->_parent->_right = cur;}}}// 左单旋void RotateL(Node* pParent) {Node* cur = pParent->_right;pParent->_right = cur->_left;cur->_left = pParent;if (pParent->_right != nullptr) {pParent->_right->_parent = pParent;}cur->_parent = pParent->_parent;pParent->_parent = cur;if (cur->_parent != nullptr) {if (cur->_parent->_left == pParent) {cur->_parent->_left = cur;}else {cur->_parent->_right = cur;}}}// 右左双旋void RotateRL(Node* pParent) {Node* cur = pParent->_right;Node* left = cur->_left;RotateR(cur);RotateL(pParent);}// 左右双旋void RotateLR(Node* pParent) {Node* cur = pParent->_left;Node* right = cur->_right;RotateL(cur);RotateR(pParent);}Node* _root = nullptr;
};

 此时,树的结点类型,也不再是K,V而是T:

template<class T>
struct RBTreeNode
{// 这里更新控制平衡也要加入 parent指针T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& kv):_data(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}
};

        那么红黑树的修改,到这里就完成了。

三、Set与Map的封装

3.1 Set

        由于对红黑树进行了一系列修改,那么,我们只需要增加一个读取数据中K值的伪函数,然后传入红黑树即可:

template<class K>
class set
{typedef K ValueType;struct KeyOfValue{const K& operator()(const ValueType& data){return data;}};typedef RBTree<K, ValueType, KeyOfValue> RBTree;typename typedef RBTree::const_iterator iterator;typename typedef RBTree::const_iterator const_iterator;
public:set() : t() {}iterator begin() const{return t.begin();}iterator end() const{return t.end();}bool empty()const {return t == nullptr;}size_t size()const {size_t i = 0;for (auto& e : t) {i++;}return i;}///// modifypair<iterator, bool> insert(const ValueType& data) {return t.Insert(data);}void clear() {t.clear();}iterator find(const K& key) {return t.find(key);}
private:RBTree t;
};

3.2 Map

        map也是同样的,唯一需要注意的就是,需要多实现一个对operator[]的重载,在了解了原理以后,实现起来也并不困难:

template<class K, class V>
class map
{typedef pair<K, V> ValueType;struct KeyOfValue{const K& operator()(const ValueType& data){return data.first;}};typename typedef RBTree<K, pair<const K, V>, KeyOfValue>::iterator iterator;typename typedef RBTree<K, pair<const K, V>, KeyOfValue>::const_iterator const_iterator;
public:map() : t() {}iterator begin() {return t.begin();}iterator end() {return t.end();}const_iterator begin() const{return t.begin();}const_iterator end() const{return t.end();}bool empty()const {return t == nullptr;}size_t size()const {size_t i = 0;for (auto& e : t) {i++;}return i;}V& operator[](const K& key) {pair<iterator, bool> a = t.Insert(make_pair(key,V()));return a.first->second;}pair<iterator, bool> insert(const ValueType& data) {return t.Insert(data);}void clear() {t.clear();}iterator find(const K& key) {return t.find(key);}
private:RBTree<K, pair<const K, V>, KeyOfValue> t;
};

 

 

        

http://www.lqws.cn/news/162973.html

相关文章:

  • Python训练第四十五天
  • 【C#】异步和多线程
  • 力扣HOT100之二分查找: 34. 在排序数组中查找元素的第一个和最后一个位置
  • 【高等数学】函数项级数
  • C获取unix操作系统的信息
  • python版若依框架开发:前端开发规范
  • spring4第7-8课-AOP的5种通知类型+切点定义详解+执行顺序
  • 3D Web轻量化引擎HOOPS Communicator三大可视化应用场景,解析浏览器支持功能!
  • 指针的使用——基本数据类型、数组、结构体
  • opencv-python的使用——from official tutorial(持续更新)
  • Git Svn
  • 今日学习:工程问题(场景题)
  • 数据库三范式设计---小白初学+案例引入
  • 一键切换不同状态,3D数字孪生场景搭建更便捷!
  • Amazing晶焱科技:电子系统产品在多次静电放电测试后的退化案例
  • React 第五十四节 Router中useRevalidator的使用详解及案例分析
  • [大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
  • MySQL——视图 用户管理 语言访问
  • 应用app的服务器如何增加高并发
  • Linux 里 su 和 sudo 命令这两个有什么不一样?
  • 【快速预览经典深度学习模型:CNN、RNN、LSTM、Transformer、ViT全解析!】
  • 每日算法刷题Day23 6.5:leetcode二分答案3道题,用时1h40min(有点慢)
  • CICD实战(一) -----Jenkins的下载与安装
  • HarmonyOS:如何在启动框架中初始化HMRouter
  • 【Redis】笔记|第10节|京东HotKey实现多级缓存架构
  • Sentinel微服务保护
  • Day45
  • 2025年ESWA SCI1区TOP,元组引导差分进化算法TLDE+黑箱优化,深度解析+性能实测
  • 如何使用 Redis 快速实现布隆过滤器?
  • 亲测解决The scripts pylupdate5.exe, pyrcc5.exe and pyuic5.exe which is not on PATH