之前介绍了红黑树,现在就利用红黑树来模拟实现简化版本的set和map。
我们之前接触过的部分容器,比如:vector、list、deque、forward_list(C++11)等,
这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
关联式容器也是用来存储数据的,但与序列式容器不同的是,
其里面存储的是
在数据检索时比序列式容器效率更高。
键值对:
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。
比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair()
: first(T1())
, second(T2())
{}
pair(const T1& a, const T2& b)
: first(a)
, second(b)
{}
};
根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。
树型结构的关联式容器主要有四种:map、set、multimap、multiset。
这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。
注意:
void test_set1()
{
set<int> s;
s.insert(5);
s.insert(2);
s.insert(3);
s.insert(3);
s.insert(1);
s.insert(1);
s.insert(1);
s.insert(4);
s.insert(4);
// 排序+去重
set<int>::iterator it = s.begin();
while (it != s.end())
{
//*it += 1; // 普通迭代器和const迭代器都是不允许修改的
cout << *it << " ";
++it;
}
cout << endl; // 1 2 3 4 5
for (auto e : s)
{
cout << e << " ";
}
cout << endl; // 1 2 3 4 5
}
注意:普通迭代器和const迭代器都是不允许修改的。这一点我们从底层源代码也能发现端倪。
const_iterator find (const value_type& val) const;
iterator find (const value_type& val);
注意使用find的时候,需要结合条件判断
void test_set2()
{
set<int> s;
s.insert(4);
s.insert(5);
s.insert(2);
s.insert(1);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(1);
set<int>::iterator pos = s.find(2); // O(logN)
if (pos != s.end())
{
cout << "set.find找到了" << endl;
}
else
{
cout << "set.find找不到" << endl;
}
// set.find找到了
pos = find(s.begin(), s.end(), 20); // O(N) 算法里的查找是暴力查找
if (pos != s.end())
{
cout << "全局find找到了" << endl;
}
else
{
cout << "全局find找不到" << endl;
}
// 全局find找不到
}
set 里面的 find 效率比较高,是 l o g n log n logn 级别的
而 algorithm 里面的 find 效率较低,属于暴力查找, O ( N ) O(N) O(N) 级别
(1)
iterator erase (const_iterator position);
(2)
size_type erase (const value_type& val);
(3)
iterator erase (const_iterator first, const_iterator last);
void test_set3()
{
set<int> s;
s.insert(4);
s.insert(5);
s.insert(2);
s.insert(1);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(1);
cout << s.erase(3) << endl; // 1 返回删除元素数量
cout << s.erase(30) << endl; // 0
for (auto e : s)
{
cout << e << " ";
}
cout << endl; // 1 2 4 5
set<int>::iterator pos = s.find(3);
if (pos != s.end())
s.erase(pos); // 如果直接删除不存在的元素 会报错
for (auto e : s)
{
cout << e << " ";
}
cout << endl; // 1 2 4 5
int x;
while (cin >> x)
{
set<int>::iterator pos = s.find(x);
if (pos != s.end())
{
s.erase(pos);
cout << "删除" << x << "成功" << endl;
}
else
{
cout << x << "不在set中" << endl;
}
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
}
}
size_type count (const value_type& val) const;
count 这个函数其实是为可以存储相同元素的 multiset 准备的。
用count 来判断元素在不在,也比用find会方便一点。
void test_set4()
{
std::set<int> myset;
// set some initial values:
for (int i = 1; i < 5; ++i) myset.insert(i * 3); // set: 3 6 9 12
for (int i = 0; i < 10; ++i)
{
std::cout << i;
if (myset.count(i) != 0)
std::cout << " is an element of myset.\n";
else
std::cout << " is not an element of myset.\n";
}
cout << endl;
for (int i = 0; i < 10; ++i)
{
std::cout << i;
if (myset.find(i) != myset.end())
std::cout << " is an element of myset.\n";
else
std::cout << " is not an element of myset.\n";
}
/*0 is not an element of myset.
1 is not an element of myset.
2 is not an element of myset.
3 is an element of myset.
4 is not an element of myset.
5 is not an element of myset.
6 is an element of myset.
7 is not an element of myset.
8 is not an element of myset.
9 is an element of myset.
0 is not an element of myset.
1 is not an element of myset.
2 is not an element of myset.
3 is an element of myset.
4 is not an element of myset.
5 is not an element of myset.
6 is an element of myset.
7 is not an element of myset.
8 is not an element of myset.
9 is an element of myset.*/
}
iterator lower_bound (const value_type& val);
const_iterator lower_bound (const value_type& val) const;
也就是说返回的是 >= val 的值,没有 val 就返回 val 的下一个。
void test_set5()
{
set<int> s;
s.insert(4);
s.insert(5);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(7);
s.insert(9);
// 返回>= val得位置迭代器 3返回3位置 6返回7位置
//set::iterator lowIt = s.lower_bound(3); // 存在
//lowIt = s.lower_bound(6); // 不存在
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 要求删除>=x的所有值
int x;
cin >> x;
set<int>::iterator lowIt = s.lower_bound(x);
s.erase(lowIt, s.end());
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
}
iterator upper_bound (const value_type& val);
const_iterator upper_bound (const value_type& val) const;
返回的是 > val 的迭代器位置。
如果都大于,返回的就是 set::end()
void test_set6()
{
set<int> s;
s.insert(4);
s.insert(5);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(7);
s.insert(9);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 返回>x位置的迭代器 -》 都是返回 7位置的迭代器
//set::iterator upIt = s.upper_bound(5); // 存在
//upIt = s.upper_bound(6); // 不存在
// 删除x <= <= y的区间 删除 [x,y]
int x, y;
cin >> x >> y;
auto leftIt = s.lower_bound(x); // [
auto rightIt = s.upper_bound(y); // )
s.erase(leftIt, rightIt);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
}
multiset 可以存储重复元素,也是包含在 set 头文件里面。
可以做到排序不去重,接口和 set 基本一致。
void test_set7()
{
multiset<int> s;
s.insert(4);
s.insert(5);
s.insert(2);
s.insert(1);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(1);
s.insert(3);
s.insert(3);
s.insert(3);
s.insert(3);
// 排序
set<int>::iterator it = s.begin();
while (it != s.end())
{
//*it = 10; /err
cout << *it << " ";
++it;
}
cout << endl; // 1 1 1 2 2 3 3 3 3 3 4 5
for (auto e : s)
{
cout << e << " ";
}
cout << endl; // 1 1 1 2 2 3 3 3 3 3 4 5
cout << s.count(1) << endl; // 3 返回1的个数
cout << s.erase(1) << endl; // 3
for (auto e : s)
{
cout << e << " ";
}
cout << endl; // 2 2 3 3 3 3 3 4 5
// 多个x的话,find返回中序第一个x
// 只有中序第一个3开始 才能遍历所有的3 左根右
auto pos = s.find(3);
while (pos != s.end())
{
cout << *pos << " ";
++pos;
}
cout << endl; // 3 3 3 3 3 4 5
}
key: 键值对中key的类型
T: 键值对中value的类型
Compare: 比较器的类型,map 中的元素是按照 key 来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器。
在 map 的内部,key 与 value 通过成员类型 value_type 绑定在一起,为其取别名称为 pair 。
make_pair 的方便在于可以自动推导类型。
insert文档
插入失败的意思表明这是冗余数据
void test_map1()
{
map<string, string> dict;
// 利用 pair 的构造函数插入数据
dict.insert(pair<string, string>("sort", "排序")); // 匿名对象
pair<string, string> kv("insert", "插入");
dict.insert(kv);
// make_pair 函数模板
dict.insert(make_pair("left", "左边"));
// C++11 才支持
//dict.insert({ "right", "右边" });
// 遍历
//map::iterator it = dict.begin();
auto it = dict.begin();
while (it != dict.end())
{
//cout << *it << " "; // it->operator*()
//cout << (*it).first << ":" << (*it).second << endl;
cout << it->first << ":" << it->second << endl; // 省略了一个 ->
++it;
}
cout << endl;
for (const auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
}
void test_map2()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
map<string, int> countMap;
for (auto& str : arr)
{
map<string, int>::iterator it = countMap.find(str);
if (it != countMap.end())
{
it->second++;
}
else
{
countMap.insert(make_pair(str, 1));
}
}
for (const auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
//苹果:6
//西瓜 : 3
//香蕉 : 2
}
利用 erase 返回值的特点,重新统计水果出现次数
ret.first 是迭代器
void test_map2()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
map<string, int> countMap;
for (auto& str : arr)
{
//pair
auto ret = countMap.insert(make_pair(str, 1));
if (ret.second == false)
{
ret.first->second++;
// ret里有一个first和secon
// first 是指向map的迭代器(指针)
// secon 是 bool 类型
}
}
for (const auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
//苹果:6
//西瓜:3
//香蕉:2
}
文档
mapped_type& operator[] (const key_type& k);
mapped_type& operator[] (key_type&& k);
mapped_tyep 其实就是 value 类型,key_type 就是 key 类型。
mapped_type& operator[] (const key_type& k)
{
return (*((this->insert(make_pair(k,mapped_type()))).first)).second
}
// 等价
mapped_type& operator[] (const key_type& k)
{
pair<map<key_type, mapped_type>::iterator, bool> ret = insert(make_pair(k, mapped_type()));
//return (*(ret.first)).second; // 等价
return ret.first->second;
}
利用 operator[] 统计水果次数
void test_map2()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
map<string, int> countMap;
for (auto& str : arr)
{
countMap[str]++; // 等价于countMap.operator[](str)++
// 第一次插入是 k不在map中,默认构造的value是0,然后立刻++变成1了
// 第二次再插入相同str,value继续++
}
for (const auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
//苹果:6
//西瓜:3
//香蕉:2
}
同样,也可以利用 operator[] 对字典进行插入、修改操作
void test_map3()
{
multimap<string, string> dict;
dict.insert(make_pair("left", "左边"));
dict.insert(make_pair("left", "剩余"));
dict.insert(make_pair("left", "左边")); // 存完全一样的value也是可以的
dict.insert(make_pair("string", "字符串"));
dict.insert(make_pair("string", "线"));
dict.insert(make_pair("string", "细绳"));
dict.insert(make_pair("string", "一系列事件"));
for (const auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
//left:左边
//left : 剩余
//left : 左边
//string : 字符串
//string : 线
//string : 细绳
//string : 一系列事件
}
注意,mulitimap没有 operator[] 接口
我们知道,set 你们是 Key,而 map 里面 Key-Value。
如何只用一个 RBTree实现既能兼容 set ,又能兼容 map 呢。
先看看STL标准库是怎么实现的吧!
红黑树节点里面存储的数据类型由 Value 决定,实现了更高维度的泛型。
既然只需要知道 Value 就可以了,那为什么还有传 Key 呢?
在某些接口函数是需要知道 Key 类型的,比如:iterator find(const K& key)
中就得知道Key的类型,才能查找,如果都用第一个的 Key 话,map 的第二个参数 pair
在insert数据时,我们需要比较data的大小。
但是对于map而已,data的类型是pair
pair文档
查文档可知,pair 的比较,first小就小,但当 first 不小而 second 小也是小。
而且我们还不能再次重载 pair 的比较运算符,因为 pair 的库里面是重载的了,只是不满足我们要求而已,如果我们再去重载就会变成重定义,编不过。
对于 set 直接用 K 比较就行,而对于 map 就得用 pair 中的first来比较。
利用仿函数。
归根结底,需要这么拐着弯去比较的原因还是因为C++语言不支持运行时比较参数的类型。如果能支持的话那么,那么我们就可以直接写出 T == Key or T != Key 这样的逻辑了。
由于 map、set 中的迭代器都是复用的红黑树中的。
其实迭代器本质上是指针的一个封装的类,是对指针的模拟。
由于标准规定,begin 和 end 必须是前闭后开。
对红黑树进行中序遍历后,可以得到一个有序的序列,因此 begin() 可以指向红黑树中最小节点(即最左侧节点)的位置,end() 指向最大节点(最右侧节点)的下一个位置即 nullptr 。
RBTree 迭代器中,比较重要的就是 operator++ 和 operator-- 。
++ 时,需要找的就是中序的下一个,按照中序左根右的访问顺序。
假设此时 it 走到5的位置,下一个应该访问6了。
假设此时 it 走到7的位置,右为空,567这个子树也访问完毕了,得去访问8了。
假设此时 it 走到8了,此时应该去访问的是12,也就是右子树的最左节点。
假设此时 it 走到12了,应该访问13,而此时12的右子树为空。
因此可以通过判断当前节点的右子树空与否来决定下一步走向。
Self& operator++(){ // 左根右
if (_node->_right == nullptr){ // 找孩子是祖先的左的祖先节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur) { // 如果是右就继续向上
cur = cur->_parent, parent = parent->_parent;
}
_node = parent; // 父亲就是要遍历的下一个节点
}
else { // 非空去找右子树最左节点
Node* subLeft = _node->_right;
while (subLeft->_left)
subLeft = subLeft->_left;
_node = subLeft;
}
return *this;
}
operator-- 同理,–相当于是倒着遍历树而已,右根左。
Self& operator--() { // 右根左 倒着走
if (_node->_left == nullptr) { // 找孩子是祖先的右的祖先节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_left) {
cur = cur->_parent, parent = parent->_parent;
}
_node = parent;
}
else { // _node->_left != nullptr
Node* subRight = _node->_left; // 最右节点
while (subRight->_right)
subRight = subRight->_right;
_node = subRight;
}
return *this;
}
迭代器部分源码
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)
:_node(node)
{}
Ref operator*(){ return _node->_data; } // 对应set就是key 对应map就是pair
Ptr operator->(){ return &_node->_data; }
Self& operator++(){ // 左根右
if (_node->_right == nullptr){ // 找孩子是祖先的左的祖先节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur) { // 如果是右就继续向上
cur = cur->_parent, parent = parent->_parent;
}
_node = parent;
}
else { // 非空去找右子树最左节点
Node* subLeft = _node->_right;
while (subLeft->_left)
subLeft = subLeft->_left;
_node = subLeft;
}
return *this;
}
Self operator++(int) {
Self tmp(*this);
++(*this);
return tmp;
}
Self& operator--() { // 右根左 倒着走
if (_node->_left == nullptr) { // 找孩子是祖先的右的祖先节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_left) {
cur = cur->_parent, parent = parent->_parent;
}
_node = parent;
}
else { // _node->_left != nullptr
Node* subRight = _node->_left; // 最右节点
while (subRight->_right)
subRight = subRight->_right;
_node = subRight;
}
return *this;
}
Self operator--(int) {
Self tmp(*this);
--(*this);
return tmp;
}
bool operator==(const Self& s) const {
return _node == s._node;
}
bool operator!=(const Self& s) const {
return _node != s._node;
}
};
set、map对迭代器的复用。
template<class K>
class set {
// ...
public:
// 取的是类模板里面的内嵌类型,里面可以带有某些没被实例化的参数
// 需要用typename 声明这些是类型,等实例化了再去对应的类模板里面取值。
typedef typename RBTree_for_map_set::RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree_for_map_set::RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const { // 这里begin的iterator是const迭代器,
// 如果不加const,那么调用的是普通版本Begin,返回的又是普通迭代器,
// const迭代器转化成普通迭代器,编不过,因此得加const,const修饰的this指针,这样就会去调用const版本Begin
// 而且普通对象也是可以调用const修饰过的begin
return _t.Begin();
}
iterator end() const {
return _t.End();
}
private:
RBTree_for_map_set::RBTree<K, K, SetKeyOfT> _t;
};
注意:
1、要加上 typename 声明后面的是类型,实例化之后再去找。
2、 set 中的 key 是不能被修改的,因此无论是 iterator 还是 const_iterator 都是复用的 RBTree 中的const_iterator 。
3、begin、end 需要加上const。
typedef typename RBTree_for_map_set::RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree_for_map_set::RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
namespace RBTree_for_map_set
{
enum Colour
{
RED,
BLACK,
};
template<class T>
struct RBTreeNode{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED)
{}
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)
:_node(node)
{}
Ref operator*(){ return _node->_data; } // 对应set就是key 对应map就是pair
Ptr operator->(){ return &_node->_data; }
Self& operator++(){ // 左根右
if (_node->_right == nullptr){ // 找孩子是祖先的左的祖先节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur) { // 如果是右就继续向上
cur = cur->_parent, parent = parent->_parent;
}
_node = parent;
}
else { // 非空去找右子树最左节点
Node* subLeft = _node->_right;
while (subLeft->_left)
subLeft = subLeft->_left;
_node = subLeft;
}
return *this;
}
Self operator++(int) {
Self tmp(*this);
++(*this);
return tmp;
}
Self& operator--() { // 右根左 倒着走
if (_node->_left == nullptr) { // 找孩子是祖先的右的祖先节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_left) {
cur = cur->_parent, parent = parent->_parent;
}
_node = parent;
}
else { // _node->_left != nullptr
Node* subRight = _node->_left; // 最右节点
while (subRight->_right)
subRight = subRight->_right;
_node = subRight;
}
return *this;
}
Self operator--(int) {
Self tmp(*this);
--(*this);
return tmp;
}
bool operator==(const Self& s) const {
return _node == s._node;
}
bool operator!=(const Self& s) const {
return _node != s._node;
}
};
// set RBTree
// map RBTree>
// KeyOfT 支持取出T对象中key的仿函数
template<class K, class T, class KeyOfT> // T决定红黑树存什么类型数据
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* subLeft = _root;
while (subLeft && subLeft->_left)
subLeft = subLeft->_left;
return iterator(subLeft); // RBTree的迭代器用节点指针就可以构造
}
iterator End() {
return iterator(nullptr);
}
const_iterator Begin() const {
Node* subLeft = _root;
while (subLeft && subLeft->_left)
subLeft = subLeft->_left;
return const_iterator(subLeft);
}
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)) // 取value出来比较
parent = cur, cur = cur->_right;
else if (kot(cur->_data) > kot(data))
parent = cur, cur = cur->_left;
else
return make_pair(iterator(cur), true);
}
cur = new Node(data);
Node* newNode = cur; // 保存好新插入的节点
cur->_col = RED; // 插入黑色一定会破坏规则4,而且规则4很难维护
if (kot(parent->_data) < kot(data))
parent->_right = cur;
else
parent->_left = cur;
cur->_parent = parent;
// 红黑树处理 ...
while (parent != nullptr && parent->_col == RED) // 存在连续红色节点
{
Node* grandFather = parent->_parent;
if (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 // uncle 不存在或者 存在且为黑 旋转处理
{
if (cur == parent->_left) // 单旋
{
// g
// p
// c
RotateR(grandFather);
parent->_col = BLACK;
grandFather->_col = RED;
}
else // 双旋
{
// g
// p
// c
RotateL(parent);
RotateR(grandFather);
cur->_col = BLACK;
grandFather->_col = RED;
}
break; // 旋转完成不需要再处理了
}
}
else // parent == grandFather->_right
{
Node* uncle = grandFather->_left;
if (uncle && uncle->_col == RED) // 情况一 存在且为红
{
parent->_col = uncle->_col = BLACK; // 变色
grandFather->_col = RED;
cur = grandFather; // 继续向上处理
parent = cur->_parent;
}
else // uncle 不存在或者 存在且为黑 旋转处理
{
if (cur == parent->_right) // 单旋
{
// g
// p
// c
RotateL(grandFather);
parent->_col = BLACK;
grandFather->_col = RED;
}
else // 双旋
{
// g
// p
// c
RotateR(parent);
RotateL(grandFather);
cur->_col = BLACK;
grandFather->_col = RED;
}
break; // 旋转完成不需要再处理了
}
}
}
_root->_col = BLACK; // 最后要确保根节点为黑色
return make_pair(iterator(newNode), true);
}
iterator Find(const K& key) {
Node* cur = _root;
KeyOfT kot;
while (cur) {
if (kot(cur->_data) < key)
cur = cur->_right;
else if (kot(cur->_data) > key)
cur = cur->_left;
else
return iterator(cur); // 相等时找到了
}
return End(); // 找不到
}
private:
void RotateR(Node* parent)
{
Node* ppNode = parent->_parent;
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
parent->_parent = subL;
if (subLR != nullptr)
subLR->_parent = parent;
subL->_right = parent;
if (parent == _root) // parent可能为根节点 旋转后更新root
_root = subL, _root->_parent = nullptr;
else
{
if (parent == ppNode->_left)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
void RotateL(Node* parent)
{
Node* ppNode = parent->_parent;
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
parent->_parent = subR;
if (subRL != nullptr) // 30的右子树可能为空
subRL->_parent = parent;
subR->_left = parent;
if (parent == _root) // parent可能为根节点 旋转完成后要更新root
_root = subR, _root->_parent = nullptr;
else // 考虑清楚是子树的右还是左 要连接ppNode 和 subR
{
if (parent == ppNode->_left)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
int _maxHeight(Node* root)
{
if (root == nullptr)
return 0;
int lh = _maxHeight(root->_left);
int rh = _maxHeight(root->_right);
return lh > rh ? lh + 1 : rh + 1;
}
int _minHeight(Node* root)
{
if (root == nullptr)
return 0;
int lh = _minHeight(root->_left);
int rh = _minHeight(root->_right);
return lh < rh ? lh + 1 : rh + 1;
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << " ";
_InOrder(root->_right);
}
bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount)
{
// 走到null之后,判断k和black是否相等
if (nullptr == pRoot)
{
if (k != blackCount)
{
cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
return false;
}
return true;
}
// 统计黑色节点的个数
if (BLACK == pRoot->_col)
++k;
// 检测当前节点与其双亲是否都为红色
if (RED == pRoot->_col && pRoot->_parent && pRoot->_parent->_col == RED)
{
cout << "违反性质三:存在连在一起的红色节点" << endl;
return false;
}
return _IsValidRBTree(pRoot->_left, k, blackCount) &&
_IsValidRBTree(pRoot->_right, k, blackCount);
}
Node* _root = nullptr;
public:
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void Height()
{
cout << "最长路径:" << _maxHeight(_root) << endl;
cout << "最短路径:" << _minHeight(_root) << endl;
}
bool IsValidRBTree() // 检查当前红黑树是否满足红黑树的几条规则
{
// 空树也是红黑树
if (nullptr == _root)
return true;
// 检测根节点是否满足情况
if (BLACK != _root->_col)
{
cout << "违反红黑树性质二:根节点必须为黑色" << endl;
return false;
}
// 获取任意一条路径中黑色节点的个数 -- 作为比较的基准值
size_t blackCount = 0;
Node* pCur = _root;
while (pCur)
{
if (BLACK == pCur->_col)
blackCount++;
pCur = pCur->_left; // 取最左路径黑色节点个数作为基准值
}
// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
size_t k = 0;
return _IsValidRBTree(_root, k, blackCount);
}
};
}
#pragma once
#include "RedBlueTree.h"
namespace yzq {
template<class K>
class set {
struct SetKeyOfT {
const K& operator()(const K& key) {
return key;
}
};
public:
// 取的是类模板里面的内嵌类型,里面可以带有某些没被实例化的参数
// 需要用typename 声明这些是类型,等实例化了再去对应的类模板里面取值。
typedef typename RBTree_for_map_set::RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree_for_map_set::RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const { // 这里begin的iterator是const迭代器,
// 如果不加const,那么调用的是普通版本Begin,返回的又是普通迭代器,
// const迭代器转化成普通迭代器,编不过,因此得加const,const修饰的this指针,这样就会去调用const版本Begin
// 而且普通对象也是可以调用const修饰过的begin
return _t.Begin();
}
iterator end() const {
return _t.End();
}
pair<iterator, bool> insert(const K& key) {
pair<typename RBTree_for_map_set::RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
// auto ret = _t.Insert(key);
return pair<iterator, bool>(iterator(ret.first._node), ret.second);
// node 是__RBTreeIterator 中的对象
}
iterator find(const K& key) {
return _t.Find(key);
}
private:
RBTree_for_map_set::RBTree<K, K, SetKeyOfT> _t;
};
void test_set1() {
set<int> s;
s.insert(8);
s.insert(6);
s.insert(11);
s.insert(5);
s.insert(6);
s.insert(7);
s.insert(10);
s.insert(13);
s.insert(12);
s.insert(15);
set<int>::iterator it = s.begin();
while (it != s.end()) {
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : s) {
cout << e << " ";
}
cout << endl;
}
}
#pragma once
#include "RedBlueTree.h"
namespace yzq {
template<class K, class V>
class map {
struct MapKeyOfT {
const K& operator()(const pair<K, V>& kv) {
return kv.first;
}
};
public:
// 取的是类模板里面的内嵌类型,里面可以带有某些没被实例化的参数
// 需要用typename 声明这些是类型,等实例化了再去对应的类模板里面取值。
typedef typename RBTree_for_map_set::RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree_for_map_set::RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin() {
return _t.Begin();
}
iterator end() {
return _t.End();
}
pair<iterator, bool> insert(const pair<K, V>& kv) {
return _t.Insert(kv);
}
iterator find(const K& key) {
return _t.Find(key);
}
V& operator[](const K& key) {
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree_for_map_set::RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
void test_map1() {
map<string, int> m;
m.insert(make_pair("111", 1));
m.insert(make_pair("555", 5));
m.insert(make_pair("333", 3));
m.insert(make_pair("222", 2));
m.insert(make_pair("999", 9));
map<string, int>::iterator it = m.begin();
while (it != m.end()) {
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
for (auto kv : m) {
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
void test_map2()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
map<string, int> countMap;
for (auto& str : arr)
countMap[str]++;
for (const auto& kv : countMap)
cout << kv.first << ":" << kv.second << endl;
//苹果:6
//西瓜 : 3
//香蕉 : 2
}
void test_map3()
{
map<string, string> dict;
dict["insert"];
dict["insert"] = "";
dict["left"] = "";
}
}
写文不易,如果有帮助烦请点个赞~
Thanks♪(・ω・)ノ
由于笔者水平有限,在今后的博文中难免会出现错误之处,本人非常希望您如果发现错误,恳请留言批评斧正,希望和大家一起学习,一起进步ヽ( ̄ω ̄( ̄ω ̄〃)ゝ,期待您的留言评论。
附GitHub仓库链接