文章目录
- 前言
- 红黑树的改变
- set的模拟实现
- 基本框架
- 迭代器
- 插入
- 源码
- map模拟实现
- 基础框架
- 迭代器
- 插入
- 赋值重载
- 源码
- 测试代码
前言
set,map底层使用红黑树这种平衡二叉搜索树来组织元素 ,这使得set, map能够提供对数时间复杂度的查找、插入和删除操作。
下面都是基于红黑树实现的set和map。
红黑树的改变
由于set和map是公用一棵树,set是K 、map是KV的结构,为了适应set与map的结构,红黑树要做出一定的改变.
- 仿函数是为了取到set内所存储的数据
- 在set的map中 set所存储的是key而map是pair
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;enum Color
{RED,BLACK
};template<class T>
struct RBTreeNode
{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Color _col;RBTreeNode(const T& data):_data(data),_left(nullptr),_right(nullptr),_parent(nullptr){}
};template<class T, class Ref, class Ptr>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;Node* _root;RBTreeIterator(Node* node,Node* root):_node(node),_root(root){}//左 -> 根 -> 右Self operator++(){//右不为空,右的最左(小)结点if (_node->_right){Node* min = _node->_right;while (min && min->_left){min = min->_left;}_node = min;}//右为空,找孩子是父亲左的结点else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self operator--(){// --end(),特殊处理,走到中序最后一个结点,整棵树的最右结点if (_node == nullptr){Node* rightMost = _root;while (rightMost && rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}// 左不为空,中序左的最右(大)结点else if (_node->_left){Node* rightMost = _node->_left;while (rightMost && rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}// 左为空,孩子是父亲右的那个祖先else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){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 _node == s._node;}bool operator!=(const Self& s) const{return _node != s._node;}
};template<class K,class T,class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;public:typedef RBTreeIterator<T, T&, T*> Iterator;typedef RBTreeIterator<T, const T&, const T*> ConstIterator;Iterator begin(){Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return Iterator(cur, _root);}Iterator end(){return Iterator(nullptr, _root);}ConstIterator begin() const{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return Iterator(cur, _root);}ConstIterator end() const{return Iterator(nullptr, _root);}pair<Iterator,bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;//return pair<Iterator, bool>(Iterator(_root, _root), true);return { Iterator(_root, _root), true };}Node* cur = _root;Node* parent = nullptr;KeyOfT kot;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return { Iterator(cur, _root), false };}}cur = new Node(data);Node* newnode = cur;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;cur->_col = RED;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;// g//p uif (parent == grandfather->_left){Node* uncle = grandfather->_right;//存在为红,变色向上调整if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}//不存在或者为黑,旋转+变色else{// g// p //cif (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}// g// p// celse{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}// g//u pelse{Node* uncle = grandfather->_left;//存在为红,变色向上调整if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}//不存在或者为黑,旋转+变色else{// g// p// cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}// g// p// celse{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return { Iterator(newnode, _root), true };}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;Node* Pparent = parent->_parent;if (subRL){subRL->_parent = parent;}parent->_right = subRL;parent->_parent = subR;subR->_left = parent;if (Pparent == nullptr){_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;Node* Pparent = parent->_parent;if (subLR){subLR->_parent = parent;}parent->_left = subLR;parent->_parent = subL;subL->_right = parent;if (Pparent == nullptr){_root = subL;subL->_parent = nullptr;}else{if (Pparent->_left == parent){Pparent->_left = subL;}else{Pparent->_right = subL;}subL->_parent = Pparent;}}void InOrder(){_InOrder(_root);cout << endl;}int Size(){return _Size(_root);}int Height(){return _Height(_root);}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if(cur->_kv.first > key){cur = cur->_left;}else{return cur;}}return nullptr;}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);}~RBTree(){Destroy(_root);_root = nullptr;}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 << ":" << root->_kv.second << "->" << root->_col << endl;_InOrder(root->_right);}int _Size(Node* root){if (root == nullptr){return 0;}return _Size(root->_left) + _Size(root->_right) + 1;}int _Height(Node* root){if (root == nullptr){return 0;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}bool Check(Node* root, int blackNum, const int refNum){if (root == nullptr){//cout << blackNum << endl;//说明一条路径已经走完了if (blackNum != refNum){cout << "存在黑色结点数量不相等的路径" << endl;return false;}return true;}if (root->_col == RED && 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);}
private:Node* _root = nullptr;
};
set的模拟实现
当前的红黑树需要这三个类型参数(键值、数据,通过数据求key的仿函数),这是为了map也能够复用,但是set只传入一个数据,所以采用这样的方式:<K, const K,SetKeyOfT< K >>,因为set中的数据是不能被修改的所以在第二个类型中加上const.
基本框架
template<class K>
class set
{struct SetKeyOfT{const K& operator()(const K& key){return key;}};
private:RBTree<K, const K,SetKeyOfT> _t;
};
迭代器
这里的迭代器直接复用红黑树的迭代器.
typedef typename RBTree<K,const K,SetKeyOfT>::Iterator iterator;
typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;iterator begin()
{return _t.begin();
}iterator end()
{return _t.end();
}const_iterator begin() const
{return _t.begin();
}const_iterator end() const
{return _t.end();
}
插入
直接复用红黑树接口,其他的接口也是同样的道理
pair<iterator,bool> insert(const K& key)
{return _t.Insert(key);
}
源码
#pragma oncenamespace mihayou
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K,const K,SetKeyOfT>::Iterator iterator;typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}pair<iterator,bool> insert(const K& key){return _t.Insert(key);}~set(){}private:RBTree<K, const K,SetKeyOfT> _t;};
}
map模拟实现
map给红黑树传的类型为:<K, pair<const K, V>, MapKeyOfT> ,K类型用于删除、查找等,pair<const K, V>作为数据插入,MapKeyOfT取pair<const K, V,>中的K类型,又因为键值不能修改所以pair<const K, V,>中的K加上const修饰.
基础框架
template<class K,class V>
class map
{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};
private:RBTree<K, pair<const K,V>,MapKeyOfT> _t;
};
迭代器
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;iterator begin()
{return _t.begin();
}iterator end()
{return _t.end();
}const_iterator begin() const
{return _t.begin();
}const_iterator end() const
{return _t.end();
}
插入
pair<iterator,bool> insert(const pair<K, V>& kv)
{return _t.Insert(kv);
}
赋值重载
在map里面,当key不存在时,重载[ ]就会用key进行插入操作并返回插入后key对应数据的引用(此时key对应数据是用其默认构造进行初始化的),当key存在时,返回key对应数据的引用。
V& operator[](const K& key)
{pair<iterator, bool> it = insert({ key,V()});return it.first->second;
}
源码
#pragma oncenamespace mihayou
{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<const K, V>, MapKeyOfT>::Iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}pair<iterator,bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}V& operator[](const K& key){pair<iterator, bool> it = insert({ key,V()});return it.first->second;}~map(){}private:RBTree<K, pair<const K,V>,MapKeyOfT> _t;};
}
测试代码
#include "RBTree.h"
#include "Myset.h"
#include "Mymap.h"
#include <string>void Print(const mihayou::set<int>& s)
{mihayou::set<int>::const_iterator it = s.end();while (it != s.begin()){--it;cout << *it << " ";}cout << endl;
}void test01()
{mihayou::set<int> s;s.insert(1);s.insert(5);s.insert(3);s.insert(7);s.insert(6);mihayou::set<int>::iterator itt = s.begin();//*itt += 10;while (itt != s.end()){cout << *itt << " ";++itt;}cout << endl;for (auto& e : s){cout << e << " ";}cout << endl;Print(s);s.~set();mihayou::map<string, string> dict;dict.insert({ "sort", "排序" });dict.insert({ "left", "左边" });dict.insert({ "right", "右边" });dict["left"] = "左边,剩余";dict["insert"] = "插入";dict["string"];mihayou::map<string, string>::iterator it = dict.begin();while (it != dict.end()){// 不能修改first,可以修改second//it->first += 'x';it->second += 'x';cout << it->first << ":" << it->second << endl;++it;}cout << endl;for (auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}dict.~map();
}int main()
{test01();return 0;
}