【C++】封装红黑树实现mymap和myset

 无论你觉得自己多么的了不起,也永远有人比你更强。💓💓💓

目录

  •✨说在前面

🍋知识点一:源码及框架分析

🍋知识点二:模拟实现map和set

•🌰1.实现出复用红黑树的框架,并支持insert

•🌰2.支持iterator的实现

•🌰3.map支持[ ]

•🌰4. map和set实现代码

 • ✨SumUp结语


  •✨说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,上一篇文章我给大家详细讲解了红黑树的实现。如果大家没有掌握好相关的知识,上一篇篇文章讲解地很详细,可以再回去看看,特别是旋转的部分,复习一下,再进入今天的内容。

我们上次给大家讲解了红黑树,我们今天就利用红黑树来封装一下map和set,再来模拟实现一下吧。建议大家先将红黑树学好,它是map和set的底层。如果大家准备好了,那就接着往下看吧~

   👇👇👇
💘💘💘知识连线时刻(直接点击即可)

【C++】AVL树实现

【C++】二叉搜索树

 AVL树的实现和测试代码

 红黑树实现及测试代码

 封装红黑树实现mymap和myset

  🎉🎉🎉复习回顾🎉🎉🎉

         

 博主主页传送门:愿天垂怜的博客

​​

🍋知识点一:源码及框架分析

SGI-STL30版本源代码,map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等几个头文件

中。大家感兴趣可以看这里:STL源码

map和set的实现结构框架核心部分截取出来如下:

// set
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_set.h>
#include <stl_multiset.h>
// map
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_map.h>
#include <stl_multimap.h>
// stl_set.h
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
	// typedefs:
	typedef Key key_type;
	typedef Key value_type;
private:
	typedef rb_tree<key_type, value_type,
		identity<value_type>, key_compare, Alloc> rep_type;
	rep_type t; // red-black tree representing set
};
// stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
	// typedefs:
	typedef Key key_type;
	typedef T mapped_type;

		typedef pair<const Key, T> value_type;
private:
	typedef rb_tree<key_type, value_type,
		select1st<value_type>, key_compare, Alloc> rep_type;
	rep_type t; // red-black tree representing map
};
// stl_tree.h
struct __rb_tree_node_base
{
	typedef __rb_tree_color_type color_type;
	typedef __rb_tree_node_base* base_ptr;
	color_type color;
	base_ptr parent;
	base_ptr left;
	base_ptr right;
};
// stl_tree.h
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc
	= alloc>
class rb_tree {
protected:
	typedef void* void_pointer;
	typedef __rb_tree_node_base* base_ptr;
	typedef __rb_tree_node<Value> rb_tree_node;
	typedef rb_tree_node* link_type;
	typedef Key key_type;
	typedef Value value_type;
public:
	// insert用的是第二个模板参数做形参
	pair<iterator, bool> insert_unique(const v
#pragma once #include "RBTree.h" namespace wusaqi { template<class K, class V> class map { struct MapkeyofT { //v在map中是pair对象 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; }; } #pragma once using namespace std; #include <iostream> enum colour { BLACK, RED }; template<class T> struct RBTNode { T _data; RBTNode<T>* _left; RBTNode<T>* _right; RBTNode<T>* _parent; colour _col; RBTNode(const T& data) :_data(data) , _left(nullptr) , _right(nullptr) , _parent(nullptr) { } }; template<class T> class __Tree_Iterator { typedef RBTNode<T> Node; typedef __Tree_Iterator<T> self; Node* _node; //Iterator的成员变量 public: __Tree_Iterator(Node* node) :_node(node) {} T& operator*() //支持返回值可以修改,不加const { return _node->_data; //返回值可能是key也可能是pair } T* operator->() //返回值是T*,只不过使用时编译器会自动优化 { return &(_node->_data); } self& operator++() //这里返回值不用加const吧? //对 { if (_node->_right) //当前结点存在右子,找右子的最左结点 { _node = _node->_right; while (_node->_left) { _node = _node->_left; } } else //当前结点不存在右子 { Node* cur = _node; Node* parent = cur->_parent; while (parent && cur == parent->_right) //若cur不为根节点或者cur在parent右边需要继续往上找 { cur = parent; parent = parent->_parent; } _node = parent; } return *this; } bool operator!=(const self& s) { //map不是要比较key的大小吗?所以__Tree_Iterator要传KeyofT吗? //迭代器比较就是单纯的比迭代器本身也就是迭代器成员变量的大小 return _node != s._node; } bool operator==(const self& s) { return _node == s._node; } }; //K是传给find/erase等函数做形参的类型的,T是真正的datatype template<class K, class T, class KeyofT> class RBTree { typedef RBTNode<T> Node; public: typedef __Tree_Iterator<T> Iterator; Iterator Begin() //找整棵最左结点 { Node* minleft = _root; while (minleft && minleft->_left) { minleft = minleft->_left; } return Iterator(minleft); } Iterator End() { return Iterator(nullptr); } bool Insert(const T& data) { if (_root == nullptr) { _root = new Node(data); _root->_col = BLACK; //根结点为黑 return true; } Node* parent = nullptr; Node* cur = _root; KeyofT kot; while (cur) { //cur->_data类型是T 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 false; } } cur = new Node(data); cur->_col = RED; //插入结点默认为红 if (kot(data) < kot(parent->_data)) parent->_left = cur; else parent->_right = cur; cur->_parent = parent; while (parent && parent->_col == RED) //更新到根结点parent为黑出循环停止更新 { Node* grandparent = parent->_parent; if (parent == grandparent->_left) //p在左,u在右 { Node* uncle = grandparent->_right; if (uncle && uncle->_col == RED) //u存在且为红 { parent->_col = uncle->_col = BLACK; grandparent->_col = RED; //继续向上调整 cur = grandparent; parent = cur->_parent; } else //u存在且为黑或不存在 { if (cur == parent->_left) //都左边小,右单旋 { // g // p u // c RotateR(grandparent); grandparent->_col = RED; parent->_col = BLACK; } else //左边小的右边大,左右双旋 { // g // p u // c RotateL(parent); RotateR(grandparent); grandparent->_col = RED; cur->_col = BLACK; //cur被推上来做根 } break; //情况2、3执行完后便更新完毕 } } else //p在右,u在左 { Node* uncle = grandparent->_left; if (uncle && uncle->_col == RED) //u存在且为红 { parent->_col = uncle->_col = BLACK; grandparent->_col = RED; //继续向上调整 cur = grandparent; parent = cur->_parent; } else //u存在且为黑或不存在 { if (cur == parent->_left) //都右边小,左单旋 { // g // u p // c RotateL(grandparent); grandparent->_col = RED; parent->_col = BLACK; } else //右边大的左边小,右左双旋 { // g // u p // c RotateR(parent); RotateL(grandparent); grandparent->_col = RED; cur->_col = BLACK; //cur被推上来做根 } break; } } } _root->_col = BLACK; //情况1cur更新到根节点需要把根结点变黑 return true; } Node* Find(const K& key) { KeyofT kot; Node* cur = _root; while (cur) { if (kot(cur->_data) < key) { cur = cur->_right; } else if (kot(cur->_data) > key) { cur = cur->_left; } else { return cur; } } return nullptr; } void InOrder() { _InOrder(_root); cout << endl; } //前序递归遍历 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); } bool IsBalance() { 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(Node* root) { if (root == nullptr) return; _InOrder(root->_left); cout << root->_kv.first << " "; _InOrder(root->_right); } void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; //? //分配孩子 subL->_right = parent; parent->_left = subLR; //调整subLR的父亲 if (subLR) subLR->_parent = subL; Node* parentParent = parent->_parent; //提前保存 //调整parent的父亲 parent->_parent = subL; //调整subL的父亲parentParent的孩子 if (parent == _root) { _root = subL; subL->_parent = nullptr; } else { subL->_parent = parentParent; if (parent == parentParent->_left) parentParent->_left = subL; else parentParent->_right = subL; } } void RotateL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; //分配孩子 subR->_left = parent; parent->_right = subRL; //调整subLR的父亲 if (subRL) subRL->_parent = subR; Node* parentParent = parent->_parent; //提前保存 //调整parent的父亲 parent->_parent = subR; //调整subL的父亲parentParent的孩子 if (parent == _root) { _root = subR; subR->_parent = nullptr; } else { subR->_parent = parentParent; if (parent == parentParent->_left) parentParent->_left = subR; else parentParent->_right = subR; } } private: Node* _root = nullptr; }; #include "myset.h" #include "mymap.h" namespace wusaqi { void test_set() { set<int> s; s.insert(4); s.insert(1); s.insert(6); s.insert(-1); s.insert(3); s.insert(9); s.insert(9); s.insert(-5); s.insert(5); s.insert(7); for (auto e : s) { cout << e << " "; } } void test_map() { map<string, string> m; m.insert({ "left", "左边" }); m.insert({ "right", "右边" }); m.insert({ "string", "字符串" }); m.insert({ "array", "数组" }); for (auto e : m) { cout << e.first << " "; } } } int main() { //wusaqi::test_set(); wusaqi::test_map(); return 0; } 为什么我用我的红黑树封装mymap插入数据会报运行错误呢,具体错误是空指针解引用,我不小心把我的红黑树哪里改了吗
08-14
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值