1. 关联式容器
STL中的部分容器,比如:vector、list、deque、 forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 存储的是元素本身。
那什么是关联式容器?它与序列式容器有什么区别?
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是结构的 键值对,在数据检索时比序列式容器效率更高。
2. 键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代 表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。
SGI-STL中关于键值对的定义:
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)
{}
};
3. 树形结构的关联式容器
根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结 构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。
迭代器的实现
下面是较为简单的迭代器重载的实现:
enum color
{
BLACK,
RED,
};
template<class v >
struct RBTNode
{
v _kv;
RBTNode<v>* _left;
RBTNode<v>* _right;
RBTNode<v>* _parent;
color _col;
RBTNode(const v& key)
:_kv(key)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
{}
};
template<class v, class ref, class ptr>
struct RBTreeIterator
{
typedef RBTNode<v> Node;
typedef RBTreeIterator<v, ref, ptr> self;
RBTreeIterator(Node* node, Node* root)
:_node(node)
, _root(root)
{}
bool operator!= (const self& key)
{
return _node != key._node;
}
bool operator==(const self& key)
{
return _node == key._node;
}
ref operator*()
{
return _node->_kv;
}
ptr operator->()
{
return &_node->_kv;
}
Node* _root;
Node* _node;
};
operator++ 的实现
it如果现在在根的位置,++寻找的是右树的最左节点。
如果右树不为空,找到右树最左节点。
右边为空,找孩子是父亲左边的祖先。
self& operator++()
{
if (_node && _node->_right)
{
Node* right = _node->_right;
while (right->_left)
{
right = right->_left;
}
_node = right;
}
else if (_node && _node->_right == nullptr)
{
Node* parent = _node->_parent;
while (parent != nullptr && _node == parent->_right)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
operator--的实现
同样的思路:
it如果现在在根的位置,++寻找的是左树的最右节点。
如果左树不为空,找到左树的最右节点。
左边为空,找孩子是父亲右边的祖先。
如果是end()-- 则需要特殊处理。
self& operator--()
{
if (_node == nullptr)
{
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
_node = right;
}
else if (_node->_left)
{
Node* left = _node->_left;
while (left->_right)
{
left = left->_right;
}
_node = left;
}
else
{
Node* parent = _node->_parent;
while (parent != nullptr && _node == parent->_left)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
Node* _root;
Node* _node;
};
RBTree中begin 和 end 的实现:
template<class k, class v, class KeyofT>
class RBTree
{
typedef RBTNode<v> Node;
public:
typedef RBTreeIterator<v, v&, v*> iterator;
typedef RBTreeIterator<v, v&, const v*> Constiterator;
iterator begin()
{
Node* root = _root;
while (root && root->_left)
{
root = root->_left;
}
return iterator(root, _root);
}
Constiterator begin() const
{
Node* root = _root;
while (root && root->_left)
{
root = root->_left;
}
return Constiterator(root, _root);
}
iterator end()
{
return iterator(nullptr, _root);
}
Constiterator end() const
{
return Constiterator(nullptr, _root);
}
private:
Node* _root = nullptr;
};
RBTree的整体代码如下:(点击目录中的set可跳过)
#include<iostream>
#include<cassert>
using namespace std;
namespace bit
{
enum color
{
BLACK,
RED,
};
template<class v >
struct RBTNode
{
v _kv;
RBTNode<v>* _left;
RBTNode<v>* _right;
RBTNode<v>* _parent;
color _col;
RBTNode(const v& key)
:_kv(key)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
{}
};
template<class v, class ref, class ptr>
struct RBTreeIterator
{
typedef RBTNode<v> Node;
typedef RBTreeIterator<v, ref, ptr> self;
RBTreeIterator(Node* node, Node* root)
:_node(node)
, _root(root)
{}
bool operator!= (const self& key)
{
return _node != key._node;
}
bool operator==(const self& key)
{
return _node == key._node;
}
ref operator*()
{
return _node->_kv;
}
ptr operator->()
{
return &_node->_kv;
}
self& operator++()
{
if (_node && _node->_right)
{
Node* right = _node->_right;
while (right->_left)
{
right = right->_left;
}
_node = right;
}
else if (_node && _node->_right == nullptr)
{
Node* parent = _node->_parent;
while (parent != nullptr && _node == parent->_right)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
self& operator--()
{
if (_node == nullptr)
{
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
_node = right;
}
else if (_node->_left)
{
Node* left = _node->_left;
while (left->_right)
{
left = left->_right;
}
_node = left;
}
else
{
Node* parent = _node->_parent;
while (parent != nullptr && _node == parent->_left)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
Node* _root;
Node* _node;
};
template<class k, class v, class KeyofT>
class RBTree
{
typedef RBTNode<v> Node;
public:
typedef RBTreeIterator<v, v&, v*> iterator;
typedef RBTreeIterator<v, v&, const v*> Constiterator;
RBTree() = default;
RBTree(const RBTree& root)
{
_root = Copy(root._root);
}
~RBTree()
{
Destroy(_root);
_root = nullptr;
}
iterator begin()
{
Node* root = _root;
while (root && root->_left)
{
root = root->_left;
}
return iterator(root, _root);
}
Constiterator begin() const
{
Node* root = _root;
while (root && root->_left)
{
root = root->_left;
}
return Constiterator(root, _root);
}
iterator end()
{
return iterator(nullptr, _root);
}
Constiterator end() const
{
return Constiterator(nullptr, _root);
}
bool empty()
{
return _root == nullptr;
}
pair<iterator, bool> Insert(const v& ret)
{
if (_root == nullptr)
{
_root = new Node(ret);
_root->_col = BLACK;
return make_pair(iterator(_root, _root), true);
}
Node* prev = nullptr;
Node* root = _root;
KeyofT key;
while (root != nullptr)
{
if (key(root->_kv) > key(ret))
{
prev = root;
root = root->_left;
}
else if (key(root->_kv) < key(ret))
{
prev = root;
root = root->_right;
}
else return make_pair(iterator(root, _root), false);
}
Node* cur = new Node(ret);
cur->_col = RED;
Node* Curnode = cur;
if (key(prev->_kv) > key(ret))
{
prev->_left = cur;
cur->_parent = prev;
}
else
{
prev->_right = cur;
cur->_parent = prev;
}
while (prev && prev->_col == RED)
{
Node* grandfather = prev->_parent;
Node* uncle = nullptr;
if (grandfather->_left == prev)
{
uncle = grandfather->_right;
}
else
{
uncle = grandfather->_left;
}
if (uncle && uncle->_col == RED)
{
prev->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
prev = cur->_parent;
}
else if (uncle == nullptr || uncle->_col == BLACK)
{
if (cur == prev->_left && grandfather->_left == prev)
{
RotetaR(grandfather);
grandfather->_col = RED;
prev->_col = BLACK;
}
else if (cur == prev->_right && grandfather->_right == prev)
{
RotetaL(grandfather);
grandfather->_col = RED;
prev->_col = BLACK;
}
else if (grandfather->_left == prev && prev->_right == cur)
{
RotetaL(prev);
RotetaR(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
else if (grandfather->_right == prev && prev->_left == cur)
{
RotetaR(prev);
RotetaL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
_root->_col = BLACK;
return make_pair(iterator(Curnode, _root), true);
}
iterator Find(const k& ret)
{
Node* root = _root;
KeyofT key;
while (root != nullptr)
{
if (key(root->_kv) > ret)
{
root = root->_left;
}
else if (key(root->_kv) < ret)
{
root = root->_right;
}
else return iterator(root, _root);
}
return end();
}
void Inorder()
{
inorder(_root);
cout << endl;
}
private:
void RotetaL(Node* prev)
{
Node* right = prev->_right;
Node* parent = prev->_parent;
prev->_right = right->_left;
if (right->_left)
{
right->_left->_parent = prev;
}
right->_left = prev;
prev->_parent = right;
if (parent == nullptr)
{
_root = right;
}
else
{
if (parent->_left == prev)
{
parent->_left = right;
}
else
{
parent->_right = right;
}
}
right->_parent = parent;
}
void RotetaR(Node* prev)
{
Node* left = prev->_left;
Node* parent = prev->_parent;
prev->_left = left->_right;
if (left->_right)
{
left->_right->_parent = prev;
}
left->_right = prev;
prev->_parent = left;
if (parent == nullptr)
{
_root = left;
}
else
{
if (parent->_left == prev)
{
parent->_left = left;
}
else
{
parent->_right = left;
}
}
left->_parent = parent;
}
void inorder(Node* root)
{
if (root == nullptr) return;
inorder(root->_left);
cout << root->_kv.first << ' ';
inorder(root->_right);
}
Node* Copy(const Node* root)
{
if (root == nullptr) return nullptr;
Node* val = new Node(root->_kv);
val->_col = root->_col;
val->_left = Copy(root->_left);
if (val->_left)
val->_left->_parent = val;
val->_right = Copy(root->_right);
if (val->_right)
val->_right->_parent = val;
return val;
}
void Destroy(Node* root)
{
if (root == nullptr) return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
Node* _root = nullptr;
};
}
4. set
4.1 set的特性
set的特性是,所有元素都会根据元素的键值自动被排序。set的元素不像map 那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,实值就是键值。set不允许两个元素有相同的键值。
我们可以通过set的迭代器改变set 的元素值吗?
不行,因为set 元素值就是其键值,关系到set元素的排列规则。如果任意改变set元素值,会严重破坏set 组织。
set拥有与list相同的某些性质:当客户端对它进行元素新增操作(insert)或删除操作(erase)时,操作之前的所有迭代器,在操作完成之后都依然有效。当然,被删除的那个元素的迭代器必然是个例外。
由于 RB-tree 是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的 STLset 即以 RB-tree 为底层机制。又由于 set 所开放的各种操作接口,RB-tree也都提供了,所以几乎所有的 set 操作行为,都只是转调用 RB-tree 的操作行为而已。
总结:
- set是按照一定次序存储元素的容器
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行 排序。
- set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对 子集进行直接迭代。
- set在底层是用二叉搜索树(红黑树)实现的。
4.2 set的框架
set的大致框架如下由于insert,empty ,拷贝构造均已经实现稍加改造直接调用即可。
template<class k>
class set
{
public:
set() = default;
set(const set<k>& key)
:_root(key._root)
{ }
pair<iterator, bool> insert(const k& key)
{
return _root.Insert(key);
}
bool empty()
{
return _root.empty();
}
private:
//因为set中的元素不能在容器中修改所以我们第二个模板类型需要加const
RBTree<k,const k, SetKeyofT> _root;
};
RBTree的 insert
由于set 和map用的是同一个 RBTree模板 但是它们的key值又不同所以这里我们需要写一个仿函数
如下:
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;
private:
RBTree<k,const k, SetKeyofT> _root;
};
RBTree的 insert改造后:
pair<iterator, bool> Insert(const v& ret)
{
if (_root == nullptr)
{
_root = new Node(ret);
_root->_col = BLACK;
return make_pair(iterator(_root, _root), true);
}
Node* prev = nullptr;
Node* root = _root;
KeyofT key;
while (root != nullptr)
{
if (key(root->_kv) > key(ret))
{
prev = root;
root = root->_left;
}
else if (key(root->_kv) < key(ret))
{
prev = root;
root = root->_right;
}
else return make_pair(iterator(root, _root), false);
}
Node* cur = new Node(ret);
cur->_col = RED;
Node* Curnode = cur;
if (key(prev->_kv) > key(ret))
{
prev->_left = cur;
cur->_parent = prev;
}
else
{
prev->_right = cur;
cur->_parent = prev;
}
while (prev && prev->_col == RED)
{
Node* grandfather = prev->_parent;
Node* uncle = nullptr;
if (grandfather->_left == prev)
{
uncle = grandfather->_right;
}
else
{
uncle = grandfather->_left;
}
if (uncle && uncle->_col == RED)
{
prev->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
prev = cur->_parent;
}
else if (uncle == nullptr || uncle->_col == BLACK)
{
if (cur == prev->_left && grandfather->_left == prev)
{
RotetaR(grandfather);
grandfather->_col = RED;
prev->_col = BLACK;
}
else if (cur == prev->_right && grandfather->_right == prev)
{
RotetaL(grandfather);
grandfather->_col = RED;
prev->_col = BLACK;
}
else if (grandfather->_left == prev && prev->_right == cur)
{
RotetaL(prev);
RotetaR(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
else if (grandfather->_right == prev && prev->_left == cur)
{
RotetaR(prev);
RotetaL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
_root->_col = BLACK;
return make_pair(iterator(Curnode, _root), true);
}
set的整体代码如下:
#include"RBTree.h"
namespace bit
{
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;
set() = default;
set(const set<k>& key)
:_root(key._root)
{ }
pair<iterator, bool> insert(const k& key)
{
return _root.Insert(key);
}
iterator begin()
{
return _root.begin();
}
const_iterator begin()const
{
return _root.begin();
}
iterator end()
{
return _root.end();
}
const_iterator end()const
{
return _root.end();
}
iterator find(const k& key)
{
return _root.Find(key);
}
bool empty()
{
return _root.empty();
}
private:
RBTree<k,const k, SetKeyofT> _root;
};
}
void testset()
{
bit::set<int> s1;
int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
//int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
//int arr[] = { 4, 2, 6,5,7 ,1, 3 };
for (auto e : arr)
{
s1.insert(e);
}
for (auto s : s1)
{
cout << s << " ";
}
cout << endl;
auto it1 = s1.end();
while (it1 != s1.begin())
{
--it1;
cout << *it1 << " ";
}
cout << endl;
for (auto e : arr)
{
it1 = s1.find(e);
cout << *it1 << " ";
}
}
5. map
5.1map的特性:
map的特性是,所有元素都会根据元素的键值自动被排序。map的所有元素都是 pair,同时拥有实值(value)和键值(key)。pair的第一元素被视为键值第二元素被视为实值。map不允许两个元素拥有相同的键值。
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair: typedef pair value_type;
- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
5.2 map的框架
namespace bit
{
template<class k, class T>
class map
{
struct MapKeyofT
{
const k& operator()(const pair<k, T>& key)
{
return key.first;
}
};
public:
typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::iterator iterator;
typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::Constiterator const_iterator;
map() = default;
map(const map<k, T>& key)
:_root(key._root)
{ }
pair<iterator, bool> insert(const pair<k, T>& key)
{
return _root.Insert(key);
}
iterator begin()
{
return _root.begin();
}
const_iterator begin()const
{
return _root.begin();
}
iterator end()
{
return _root.end();
}
const_iterator end()const
{
return _root.end();
}
iterator find(const k& key)
{
return _root.Find(key);
}
bool empty()
{
return _root.empty();
}
private:
RBTree<k, pair<const k, T>, MapKeyofT> _root;
};
}
map中的很多都与set 相似但是map 比set 多重载了operator[ ]
oparetor[ ] 的实现
所以我们可以这么写:
T& operator[](const k& key)
{
return (insert({ key, T() }).first)->second;
}
最后整体代码如下:
template<class k, class T>
class map
{
struct MapKeyofT
{
const k& operator()(const pair<k, T>& key)
{
return key.first;
}
};
public:
typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::iterator iterator;
typedef typename RBTree<k, pair<const k, T>, MapKeyofT>::Constiterator const_iterator;
map() = default;
map(const map<k, T>& key)
:_root(key._root)
{ }
pair<iterator, bool> insert(const pair<k, T>& key)
{
return _root.Insert(key);
}
iterator begin()
{
return _root.begin();
}
const_iterator begin()const
{
return _root.begin();
}
iterator end()
{
return _root.end();
}
const_iterator end()const
{
return _root.end();
}
iterator find(const k& key)
{
return _root.Find(key);
}
bool empty()
{
return _root.empty();
}
//(*((this->insert(make_pair(k,mapped_type())).first)).second
T& operator[](const k& key)
{
return (insert({ key, T() }).first)->second;
}
private:
RBTree<k, pair<const k, T>, MapKeyofT> _root;
};
void test_map()
{
std::map<string, string> dict;
dict.insert({ "sort", "排序" });
dict.insert({ "left", "左边" });
dict.insert({ "right", "右边" });
//const std::map<string, string> dict = dict1;
dict["left"];
dict["insert"];
dict["string"];
auto it = dict.begin();
while (it != dict.end())
{
// 不能修改first,可以修改second
//it->first += 'x';
it->second += 'x';
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}