改造红黑树

在初次看STL中实现红黑树的源码时有些不理解,然后自己尝试对set以RBTree<K,K>的方式封装红黑树的迭代器;实现过程发现,这样封装复用程度特别低,也特别冗余,因此才能领悟到STL源码实现红黑树复用时的精髓.下文将模拟STL的实现方式改造红黑树和封装map和set.

参考的STL版本为SGI30

适配STL迭代器的红黑树

红黑树数据操作的代码实现是旧版本的,新版本在上一篇博客中有详细分析.

本篇主要特点在迭代器适配上

基本结构

#pragma once

#include<assert.h>
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
using std::pair;
using std::make_pair;
using std::string; namespace test
{
enum Colour { RED, BLACK };
template<class T> struct RBTreeNode;
template<class T, class Ref, typename Ptr> struct __RBTree_iterator;
template<class K, class T, class keyOfT> class RBTree;
}

RBTreeNode

	template<class T> // T为key或pair,T是key或者key-value类型
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
T _data; //data是key或pair
Colour _col; RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};

__RBTree_iterator

template<class T, class Ref, typename Ptr>
struct __RBTree_iterator
{
typedef RBTreeNode<T> node;
node* _node;
__RBTree_iterator(node* node)
:_node(node)
{} //首先,<class T, class Ref, class Ptr>这种写法能够提高复用性和灵活性(实现不同类型的迭代器)等,,库里迭代器都这么写
//其次,模板参数中,T用于获取类型,Ref用于返回引用,Ptr用于返回指针 using Self = __RBTree_iterator<T,Ref,Ptr>; //自己--实例化出下面两种迭代器
using iterator = __RBTree_iterator<T,T&,T*>; //普通迭代器
using const_iterator = __RBTree_iterator<T,const T&,const T*>; //const迭代器
__RBTree_iterator(const iterator& it)
:_node(it._node)
{}
//这个构造函数的作用,
//a.当迭代器被实例化成iterator时,他就是拷贝构造函数. __RBTree_iterator<T,T&,T*>
//b.当迭代器被实例化成const_iterator时,他是支持隐式类型转换的带参构造函数. __RBTree_iterator<T,const T&,const T*> //这样实现的目的
// 能够复用普通迭代器,可以通过类型转换后直接实现出const迭代器 //Ref为 T& 或 const T&, Ptr为 T* 或 const T*
//typedef __RBTree_iterator<T, Ref, Ptr> Self; Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(_node->_data);
}
bool operator!=(const Self& x)
{
return _node != x._node;
}
//前置++
Self& operator++() {
//此版本实现迭代器不需要判空,为空说明遍历结束,要么是用户错误使用
Node* cur = _node;
//1. 有右子树
if (cur->_right) {
//找右子树的最小结点
Node* rightMin = cur->_right;
while (rightMin->_left) {
rightMin = rightMin->_left;
}
_node = rightMin;
}
//2. 没有右子树
else {
////1.没有父亲,说明是根
//Node* parent = cur->_parent;
//if (parent == nullptr) {
// _node == nullptr;
//}
////2.且我是父的左子树,说明父亲是下一个正序值
//else if (parent->_left == cur) {
// _node = parent;
//}
////3.或我是父亲的右子树,说明走完了当前最小分支祖先这棵树.迭代往上
//else if (parent->_right == cur) {
// while (parent && cur != parent->_left) {
// cur = parent;
// parent = parent->_parent;
// }
// _node = parent;
//}
//else {
// asssert(false);
//} //上面3种情况可以合并成一种情况:找最近的不是右孩子的祖父
Node* parent = cur->_parent;
while (parent && cur != parent->_left) {
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
} //后置++
Self operator++(int) {
Self tmp(_node);
operator++();
return tmp;
} Self& operator--() {
//将++反过来就是--
Node* cur = _node;
//左子树存在,就找最大
if (cur->_left) {
Node* leftMax = cur->_left;
while (leftMax->_right) {
leftMax = leftMax->_right;
}
_node = leftMax;
}
//2. 没有左子树
else {
Node* parent = cur->_parent;
while (parent && cur != parent->_right) {
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
} Self operator--(int) {
Self tmp(_node);
operator--();
return tmp;
}
};

RBTree

	//参数K用在find,erase等,虽然K也可以被T取代了,但没必要,K更快
template<class K, class T, class keyOfT> //库中还有1个compare,先不写了
class RBTree
{
public:
typedef RBTreeNode<T> node; //T是key或pair
public:
typedef __RBTree_iterator<T, T&, T*> iterator;
typedef __RBTree_iterator<T, const T&, const T*> const_iterator; iterator begin()
{
node* cur = _root;
while (cur && cur->_left)//不能走到空
{
cur = cur->_left;
}
return iterator(cur);//返回中序的第一个结点,最左结点
} iterator end() //end是最一个位置的下一个
{
return iterator(nullptr);//暂时可以这么写
} const_iterator begin()const
{
node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
} const_iterator end() const
{
return iterator(nullptr);
} private:
node* _root = nullptr;
public:
node* find(const K& key)
{
keyOfT kot;//kot是个仿函数,根据不同参数返回不同的参数对象
node* cur = _root;
while (cur)
{
if (key < kot(cur->_data)) // -------------------------------------------- 只需要重载一个 '<' 或 '>' 就可以比较大小
{
cur = cur->_left;
}
else if (kot(cur->_data) < key) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
} pair<iterator, bool> insert(const T& data)
{
if (!_root)
{
_root = new node(data);
_root->_col = BLACK;
return std::make_pair(iterator(_root), true);
} keyOfT kot; node* cur = _root;
node* parent = nullptr;
while (cur)
{
if (kot(cur->_data) < kot(data) ) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
parent = cur;
cur = cur->_right;
}
else if (kot(data) < kot(cur->_data)) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
parent = cur;
cur = cur->_left;
}
else
{
return std::make_pair(iterator(cur), false);
}
}
cur = new node(data);
if ( kot(parent->_data) < kot(data)) // --------------------------------------------
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent; //调整/旋转
node* newnode = cur;//调整过程cur会发生变化,将cur结点记住 -- 记住原来key的位置
while (parent && parent->_col == RED)
{
node* g = parent->_parent;
if (parent == g->_right)
{
node* u = g->_left;
if (u && u->_col == RED)
{
g->_col = RED;
parent->_col = BLACK;
u->_col = BLACK;
cur = g;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(g);
parent->_col = BLACK;
g->_col = RED;
}
else
{
RotateR(parent);
RotateL(g);
g->_col = RED;
cur->_col = BLACK;
}
break;
} }
else
{
node* u = g->_right;
if (u && u->_col == RED)
{
g->_col = RED;
parent->_col = BLACK;
u->_col = BLACK;
cur = g;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(g);
parent->_col = BLACK;
g->_col = RED;
}
else
{
RotateL(parent);
RotateR(g);
g->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return std::make_pair(iterator(newnode), true);
}
public:
void InOrderTraversal()
{
_InOrderTraversal(_root);
} bool isBalanceTree()
{
//需要判断3个规则
//1.根为黑
if (_root && _root->_col == RED)
{
cout << "错误:根是红色" << endl;
return false;
} //2.不能有连续得红
//3.黑同
int benchmark = 0;
node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
++benchmark;
}
cur = cur->_left;
}
return _check(_root, 0, benchmark);
} int Height()
{
return _Height(_root);
}
~RBTree()
{
Destroy(_root);
} private:
void Destroy(node*& root)
{
if (!root)
{
return;
}
Destroy(root->_left);
Destroy(root->_right);
delete root;
root = nullptr;
} bool _check(node* root, int blackNum, int benchmark)
{
keyOfT kot;
if (!root) //
{
if (blackNum != benchmark)
{
cout << "错误:存在不同路径的黑色结点数量不相同" << endl;
return false;
}
return true;
} if (root->_col == BLACK)
{
++blackNum;
} if (root->_col == RED && root->_parent->_col == RED)
{
cout << kot(root->_data) << " 错误,与父节点同时为红色"; // --------------------------------------------
return false;
} return _check(root->_left, blackNum, benchmark) && _check(root->_right, blackNum, benchmark);
} int _Height(node* root)
{
if (!root)
{
return 0;
}
int leftH = _Height(root->_left);
int rightH = _Height(root->_right); return leftH > rightH ? leftH + 1 : rightH + 1;
} void _InOrderTraversal(node* root)
{
keyOfT kot;
if (root == nullptr)
{
return;
}
_InOrderTraversal(root->_left);
cout << kot(root->_data) << " "; // --------------------------------------------
_InOrderTraversal(root->_right);
} void RotateL(node* parent)
{
node* subR = parent->_right;
node* subRL = subR->_left; parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
} node* pparent = parent->_parent; subR->_left = parent;
parent->_parent = subR; if (!pparent)
{
_root = subR;
_root->_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; parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
} node* pparent = parent->_parent; subL->_right = parent;
parent->_parent = subL; if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
}
};

完整代码

#pragma once

#include<assert.h>
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
using std::pair;
using std::make_pair;
using std::string; namespace test
{ //与库中的RBT差异
/**
*
* 库中还有结点数量 count
*
* 库中RBT是带头结点哨兵卫的,头结点的左是中序第一个(最小结点),右节点是中序的最后一个(最大结点),
* 哨兵卫的parent指向根节点,根节点的parent指向哨兵卫
*
* 库中的begin直接取head的left -- 函数:leftmost() //最左结点
* 库中的end 是head的right -- 不是rightmost,rightmost是最右结点,end是最右结点的下一个
* 库中的end 需要判断一下,防止只有左子树的歪脖子树时,end == head->right,死循环
*
* 和库的区别就是end,库的end能走回到head,我的不能,只能走到空就没了d
*
*/ enum Colour { RED, BLACK }; template<class T> //T是什么,为什么只传T? T为key或pair,T是key或者key-value类型
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
T _data; //data是key或pair
Colour _col; RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
//const_iterator<T,const T&,const T*>
//iterator<T, T&, T*> template<class T, class Ref, typename Ptr>
struct __RBTree_iterator
{
typedef RBTreeNode<T> node;
node* _node;
__RBTree_iterator(node* node)
:_node(node)
{} //首先,<class T, class Ref, class Ptr>这种写法能够提高复用性和灵活性(实现不同类型的迭代器)等,,库里迭代器都这么写
//其次,模板参数中,T用于获取类型,Ref用于返回引用,Ptr用于返回指针 using Self = __RBTree_iterator<T,Ref,Ptr>; //自己--实例化出下面两种迭代器
using iterator = __RBTree_iterator<T,T&,T*>; //普通迭代器
using const_iterator = __RBTree_iterator<T,const T&,const T*>; //const迭代器
__RBTree_iterator(const iterator& it)
:_node(it._node)
{}
//这个构造函数的作用,
//a.当迭代器被实例化成iterator时,他就是拷贝构造函数. __RBTree_iterator<T,T&,T*>
//b.当迭代器被实例化成const_iterator时,他是支持隐式类型转换的带参构造函数. __RBTree_iterator<T,const T&,const T*> //这样实现的目的
// 能够复用普通迭代器,可以通过类型转换后直接实现出const迭代器 //Ref为 T& 或 const T&, Ptr为 T* 或 const T*
//typedef __RBTree_iterator<T, Ref, Ptr> Self; Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(_node->_data);
}
bool operator!=(const Self& x)
{
return _node != x._node;
}
//前置++
Self& operator++() {
//此版本实现迭代器不需要判空,为空说明遍历结束,要么是用户错误使用
Node* cur = _node;
//1. 有右子树
if (cur->_right) {
//找右子树的最小结点
Node* rightMin = cur->_right;
while (rightMin->_left) {
rightMin = rightMin->_left;
}
_node = rightMin;
}
//2. 没有右子树
else {
////1.没有父亲,说明是根
//Node* parent = cur->_parent;
//if (parent == nullptr) {
// _node == nullptr;
//}
////2.且我是父的左子树,说明父亲是下一个正序值
//else if (parent->_left == cur) {
// _node = parent;
//}
////3.或我是父亲的右子树,说明走完了当前最小分支祖先这棵树.迭代往上
//else if (parent->_right == cur) {
// while (parent && cur != parent->_left) {
// cur = parent;
// parent = parent->_parent;
// }
// _node = parent;
//}
//else {
// asssert(false);
//} //上面3种情况可以合并成一种情况:找最近的不是右孩子的祖父
Node* parent = cur->_parent;
while (parent && cur != parent->_left) {
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
} //后置++
Self operator++(int) {
Self tmp(_node);
operator++();
return tmp;
} Self& operator--() {
//将++反过来就是--
Node* cur = _node;
//左子树存在,就找最大
if (cur->_left) {
Node* leftMax = cur->_left;
while (leftMax->_right) {
leftMax = leftMax->_right;
}
_node = leftMax;
}
//2. 没有左子树
else {
Node* parent = cur->_parent;
while (parent && cur != parent->_right) {
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
} Self operator--(int) {
Self tmp(_node);
operator--();
return tmp;
}
}; //参数K用在find,erase等,虽然K也可以被T取代了,但没必要,K更快
template<class K, class T, class keyOfT> //库中还有1个compare,先不写了
class RBTree
{
public:
typedef RBTreeNode<T> node; //T是key或pair
public:
typedef __RBTree_iterator<T, T&, T*> iterator;
typedef __RBTree_iterator<T, const T&, const T*> const_iterator; iterator begin()
{
node* cur = _root;
while (cur && cur->_left)//不能走到空
{
cur = cur->_left;
}
return iterator(cur);//返回中序的第一个结点,最左结点
} iterator end() //end是最一个位置的下一个
{
return iterator(nullptr);//暂时可以这么写
} const_iterator begin()const
{
node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
} const_iterator end() const
{
return iterator(nullptr);
} private:
node* _root = nullptr;
public:
node* find(const K& key)
{
keyOfT kot;//kot是个仿函数,根据不同参数返回不同的参数对象
node* cur = _root;
while (cur)
{
if (key < kot(cur->_data)) // -------------------------------------------- 只需要重载一个 '<' 或 '>' 就可以比较大小
{
cur = cur->_left;
}
else if (kot(cur->_data) < key) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
} pair<iterator, bool> insert(const T& data)
{
if (!_root)
{
_root = new node(data);
_root->_col = BLACK;
return std::make_pair(iterator(_root), true);
} keyOfT kot; node* cur = _root;
node* parent = nullptr;
while (cur)
{
if (kot(cur->_data) < kot(data) ) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
parent = cur;
cur = cur->_right;
}
else if (kot(data) < kot(cur->_data)) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
parent = cur;
cur = cur->_left;
}
else
{
return std::make_pair(iterator(cur), false);
}
}
cur = new node(data);
if ( kot(parent->_data) < kot(data)) // --------------------------------------------
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent; //调整/旋转
node* newnode = cur;//调整过程cur会发生变化,将cur结点记住 -- 记住原来key的位置
while (parent && parent->_col == RED)
{
node* g = parent->_parent;
if (parent == g->_right)
{
node* u = g->_left;
if (u && u->_col == RED)
{
g->_col = RED;
parent->_col = BLACK;
u->_col = BLACK;
cur = g;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(g);
parent->_col = BLACK;
g->_col = RED;
}
else
{
RotateR(parent);
RotateL(g);
g->_col = RED;
cur->_col = BLACK;
}
break;
} }
else
{
node* u = g->_right;
if (u && u->_col == RED)
{
g->_col = RED;
parent->_col = BLACK;
u->_col = BLACK;
cur = g;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(g);
parent->_col = BLACK;
g->_col = RED;
}
else
{
RotateL(parent);
RotateR(g);
g->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return std::make_pair(iterator(newnode), true);
}
public:
void InOrderTraversal()
{
_InOrderTraversal(_root);
} bool isBalanceTree()
{
//需要判断3个规则
//1.根为黑
if (_root && _root->_col == RED)
{
cout << "错误:根是红色" << endl;
return false;
} //2.不能有连续得红
//3.黑同
int benchmark = 0;
node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
++benchmark;
}
cur = cur->_left;
}
return _check(_root, 0, benchmark);
} int Height()
{
return _Height(_root);
}
~RBTree()
{
Destroy(_root);
} private:
void Destroy(node*& root)
{
if (!root)
{
return;
}
Destroy(root->_left);
Destroy(root->_right);
delete root;
root = nullptr;
} bool _check(node* root, int blackNum, int benchmark)
{
keyOfT kot;
if (!root) //
{
if (blackNum != benchmark)
{
cout << "错误:存在不同路径的黑色结点数量不相同" << endl;
return false;
}
return true;
} if (root->_col == BLACK)
{
++blackNum;
} if (root->_col == RED && root->_parent->_col == RED)
{
cout << kot(root->_data) << " 错误,与父节点同时为红色"; // --------------------------------------------
return false;
} return _check(root->_left, blackNum, benchmark) && _check(root->_right, blackNum, benchmark);
} int _Height(node* root)
{
if (!root)
{
return 0;
}
int leftH = _Height(root->_left);
int rightH = _Height(root->_right); return leftH > rightH ? leftH + 1 : rightH + 1;
} void _InOrderTraversal(node* root)
{
keyOfT kot;
if (root == nullptr)
{
return;
}
_InOrderTraversal(root->_left);
cout << kot(root->_data) << " "; // --------------------------------------------
_InOrderTraversal(root->_right);
} void RotateL(node* parent)
{
node* subR = parent->_right;
node* subRL = subR->_left; parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
} node* pparent = parent->_parent; subR->_left = parent;
parent->_parent = subR; if (!pparent)
{
_root = subR;
_root->_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; parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
} node* pparent = parent->_parent; subL->_right = parent;
parent->_parent = subL; if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
}
};
}

封装的set

红黑树改造完成后,封装set和map就比较简单了,基本上都是套用红黑树的功能,特别方便,这也体会到了实现STL的大佬们的厉害.

#pragma once

#include"RBT.hpp"
namespace test
{ template<class K>
class set
{ private:
struct setKeyOfT//取出RBT的类型T中的key
{
const K& operator()(const K& key)
{
return key;
}
};
private:
RBTree< K, K, setKeyOfT>_t;
public:
//使用类域的要加typename,以防和静态变量冲突
typedef typename RBTree<K, K, setKeyOfT>::const_iterator iterator; //普通迭代器
typedef typename RBTree<K, K, setKeyOfT>::const_iterator const_iterator; //const迭代器 iterator begin()
{
return _t.begin(); //begin是普通迭代器,返回值是const,发生隐式类型转换(单参数)
//如果有相应的构造函数,则支持隐式类型转换 ,但此时迭代器没有参数为迭代器的构造函数,需要添加
}
iterator end()
{
return _t.end();
} const_iterator begin()const
{
return _t.begin();
}
const_iterator end()const
{
return _t.end();
} public:
pair<iterator, bool> insert(const K& key)
{
return _t.insert(key);
} }; void test_mySet1()
{
test::set<int> s;
s.insert(2);
s.insert(1);
s.insert(3); set<int>::iterator it = s.begin();
//while (it!=s.end())
//{
// cout << *it << " ";
// ++it;
//}
for (auto& e : s)
{
cout << e << " ";
}
cout << *++it << " ";
cout << *--it << " ";
cout << endl;
//*it = 1;////不允许赋值,表达式必须是可以修改的左值 .不能给常量赋值 }
}

封装的map

#pragma once

#include"RBT.hpp"
namespace test
{
template<class K,class V>
class map
{
private:
struct mapKeyOfT
{
const K& operator()(const pair<const K,V>& kv)
{
return kv.first;
}
};
private:
RBTree<K, pair<const K, V>, mapKeyOfT> _t;
public:
typedef typename RBTree<K, pair<const K,V>, mapKeyOfT>::iterator iterator; iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
} public:
pair<iterator,bool> insert(const pair<const K, V>& kv)
{
return _t.insert(kv);
} V& operator[](const K& key)
{
pair<iterator,bool> ret = insert(make_pair(key, V()));
return ret.first->second;
} }; void test_myMap1()
{
test::map<int, int> m;
m.insert(std::make_pair(1, 1));
m.insert(std::make_pair(3, 3));
m.insert(std::make_pair(2, 2));
test::map<int,int>::iterator it = m.begin();
//while (it != m.end())
//{
// cout << it->first << " ";
// ++it;
//}
for (auto e : m)
{
cout << e.first << " ";
} cout << (++it)->first << " ";
cout << (--it)->first << " ";
cout << endl; //it->second = 1; //可以赋值
//it->first = 1;//不允许赋值,表达式必须是可以修改的左值 .不能给常量赋值
} void test_myMap2()
{
//map的使用
map<std::string, std::string> dict;
dict.insert(std::pair<std::string, std::string>("sort", "排序")); //匿名对象插入
dict.insert(std::make_pair("string", "字符串")); //pair封装插入
dict.insert(std::make_pair("count", "计数"));
dict.insert(std::make_pair("count", "(计数)")); //插入失败的
auto it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
} void test_myMap3()
{
std::string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
map<std::string, int> countMap;
/*for (auto e : arr)
{
auto ret = countMap.find(x);
if (ret==countMap.end())
{
countMap.insert(std::pair<string, int>(x, 1));
}
else
{
++ret->second;
}
}*/ for (auto& e : arr)
{
++countMap[e];
} for (auto& s : countMap)
{
cout << s.first << ":" << s.second << endl;
}
}
}

STL 改造红黑树 模拟封装set和map的更多相关文章

  1. SGI STL红黑树中迭代器的边界值分析

    前言 一段程序最容易出错的就是在判断或者是情况分类的边界地方,所以,应该对于许多判断或者是情况分类的边界要格外的注意.下面,就分析下STL中红黑树的迭代器的各种边界情况.(注意:分析中STL使用的版本 ...

  2. stl vector、红黑树、set、multiset、map、multimap、迭代器失效、哈希表(hash_table)、hashset、hashmap、unordered_map、list

    stl:即标准模板库,该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法 六大组件: 容器.迭代器.算法.仿函数.空间配置器.迭代适配器 迭代器:迭代器(iterator)是一种抽象的设计 ...

  3. stl map底层之红黑树插入步骤详解与代码实现

    转载注明出处:http://blog.csdn.net/mxway/article/details/29216199 本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进 ...

  4. [转]SGI STL 红黑树(Red-Black Tree)源代码分析

    STL提供了许多好用的数据结构与算法,使我们不必为做许许多多的重复劳动.STL里实现了一个树结构-Red-Black Tree,它也是STL里唯一实现的一个树状数据结构,并且它是map, multim ...

  5. PAT (Advanced Level) 1132~1135:1132 模拟 1133模拟(易超时!) 1134图 1135红黑树

    1132 Cut Integer(20 分) 题意:将一个含K(K为偶数)个数字的整数Z割分为A和B两部分,若Z能被A*B整除,则输出Yes,否则输出No. 分析:当A*B为0的时候,不能被Z整除,输 ...

  6. 【stl学习笔记】红黑树

    转自维基百科 红黑树是一种平衡二叉搜索树,它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目. 性质: 红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色.在二叉查找 ...

  7. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  8. AVL树、splay树(伸展树)和红黑树比较

    AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...

  9. 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树

    某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...

  10. 谈c++ pb_ds库(二) 红黑树大法好

    厉害了,没想到翻翻pb_ds库看到这么多好东西,封装好的.现成的splay.红黑树.avl... 即使不能在考场上使用也可以用来对拍哦 声明/头文件 #include <ext/pb_ds/tr ...

随机推荐

  1. HDFS的特点和目标,不适合场景

     HDFS的特点和目标: HDFS设计优点: (一)高可靠性:Hadoop按位存储和处理数据的能力值得人们信赖; (二)高扩展性:Hadoop是在可用的计算机集簇间分配数据并完成计算任务的,这些集簇可 ...

  2. 使用kafka作为生产者生产数据_到_hbase

    配置文件: agent.sources = r1agent.sinks = k1agent.channels = c1 ## sources configagent.sources.r1.type = ...

  3. Java高效率查询Mysql节点树数据

    示例 目前有一个功能:任务计划管理,必然存在多级子任务的父子级关系,每个任务还会存在其它数据的关联表. mysql无法一次性递归查出想要的数据结构,想必很多人都会是通过根目录递归查询数据库的方式查出树 ...

  4. yb课堂之高并发项目必备利器之分布式缓存和本地缓存 《十九》

    什么是缓存? 程序经常要调用的对象存储在内存中,方便其使用时可以快速调用,不必去数据库或者其他持久化设备中查询,主要就是提高性能 DNS.前端缓存.代理服务器缓存Nginx.应用程序缓存(本地缓存.分 ...

  5. 如何在有数BI中实现千人千面的数据推送?

    问题背景 前几天有个项目管理的同学来咨询我一个问题,该项目有一个项目进度信息表,表中有项目名称,项目阶段,项目状态,项目任务等字段,在实际工作中想要实现如下场景: 当项目名称为A时,且项目阶段是需求阶 ...

  6. MySql(Innodb)事务隔离级别

    事务将数据库从一个一致状态转换至另外一个一致状态,若某个事务看到了另外一个事务在状态转换过程中的中间态数据(不一致状态),将有可能导致另外一个事务的操作基于一个不一致的数据库状态,进而数据库失去一致性 ...

  7. oeasy 教您玩转 linux 之 010302 火狐浏览器 firefox

    我们来回顾一下 上一部分我们都讲了什么? oneko xeyes 这次看看这个火狐 火狐 看看当前版本 看看是否可以更新 如果需要更新就更新    firefox -v    apt search f ...

  8. layui表格列添加超链接并传参

    1.表格渲染中对列添加templet属性  addlink为方法名 tableIns = table.render({                elem: '#Test'            ...

  9. BI 工具助力企业解锁数字化工厂,开启工业智能新视界

    背景 在 2022 年公布的<"十四五"数字经济发展规划>中,政府不断增加对制造业数字化转型的政策支持力度,积极倡导制造企业采用最新技术,提升自动化.数字化和智能化水平 ...

  10. 第九讲: MySQL为什么有时候会选错索引?

    第九讲: MySQL为什么有时候会选错索引? ​ 前面我们介绍过索引,你已经知道了在 MySQL 中一张表其实是可以支持多个索引的. ​ 但是,你写 SQL 语句的时候,并没有主动指定使用哪个索引.也 ...