set的内部实现是基于红黑树,set就是以红黑树的格式存储内部的所有元素的。
set中的所有元素都会根据元素的键值自动被排序。set的元素不像map那样可以同时拥有实值(value)和键值(key)。set中只有一个值,set不允许两个元素有相同的值。
我们不可以使用迭代器修改set的元素值,元素值已经按照红黑树的方式排列好,如果修改就会改变其组织。set中,可以允许删除和增加一些元素。
map的内部实现同样是基于红黑树。
和set不同,map的所有元素都是一个键值对pair(key,value),所有元素都会按照key的值进行排序,map中不允许有相同的key值,但可以修改map中元素的value值。
而multiset和multimap的特性和set和map一样,唯一的差别是允许key重复
1 set和multiset
set和multiset会根据特定的排序准则,自动将元素进行排序。不同的是后者允许元素重复而前者不允许。
set和multiset两种头文件都为:#include<set>
set和multiset都是定义在std空间里的类模板。
template < class T, // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;
template < class T, // multiset::key_type/value_type
class Compare = less<T>, // multiset::key_compare/value_compare
class Alloc = allocator<T> > // multiset::allocator_type
> class multiset;
其中第二个参数来定义排序准则为仿函数,默认为less,也就意味着,默认遍历结果为升序。例:
set<int,greater<int>> s1;
s1.insert(10);
s1.insert(3);
s1.insert(9);
s1.insert(8);
s1.insert(1);
s1.insert(3);
set<int,greater<int>>::iterator it1 = s1.begin();
while (it1 != s1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
运行结果:
相关操作
1.1 插入
插入用insert函数
pair<iterator,bool> insert (const value_type& val);//pair::first set to an iterator pointing to either the newly inserted element or to the equivalent element already in the set. The pair::second element in the pair is set to true if a new element was inserted or false if an equivalent element already existed.
iterator insert (iterator position, const value_type& val);//在指定的位置插入指定的数据,position是一个迭代器的位置,x表示的是要插入的数。如果插入成功的话,会返回一个插入新位置的迭代器。
template <class InputIterator>
void insert (InputIterator first, InputIterator last);//插入一个迭代器区间
pair是一种模板模型,每个pair可以存储两个值,这俩个值得类型是任意类型。定义在#include中,其标准形式为:template< class T1,class T2> struct pair;
pair有两个成员分别是first和second,set是一个模板,first是一个指向要插入位置的迭代器,如果second是false则first就是已经存在的元素的这个位置的迭代器,如果second为true,first就是要插入位置的迭代器。
结构如下:
template<class K,class V>
class pair
{
public:
pair(const K& key, const V& v)
:first(key)
, second(v)
{ }
const K first;
V second;
};
例:
set<int> myset;
set<int>::iterator it;
pair<iterator,bool> ret;
// 初始化
for (int i=1; i<=5; ++i) myset.insert(i*10);
ret = myset.insert(20); //20存在,插入失败
if (ret.second==false) it=ret.first; // it指向20
myset.insert (it,25);
myset.insert (it,24);
myset.insert (it,26);
int myints[]= {5,10,15};
myset.insert (myints,myints+3);
for (it=myset.begin(); it!=myset.end(); ++it)
cout << ' ' << *it;
cout << '\n';
1.2 查找
查找用find()函数
iterator find(const key_type& x) const;//若找到返回该迭代器的位置,否则就返回的是最后一个元素后面的位置
使用count()函数
size_type count(const key_type& x)const;//count是为了统计某个数值出现的次数,在set里面不能重复出现相同的数值,count的返回值只有0和1两个值,0表示的是不存在,1表示存在。
例:
set<int> s3;
s3.insert(10);
s3.insert(3);
s3.insert(9);
s3.insert(8);
s3.insert(1);
s3.insert(3);
set<int>::iterator pos = s3.find(10);//当迭代器没找到返回end,end是最后一个数据的下一个
if (s3.count(8))
{
cout << "exit" << endl;
}
else
{
cout << "Non" << endl;
}
1.3 删除
void erase(iterator position)//删除一个迭代器位置
size_type erase(sonst key_type& x)//删除成功的话就返回1
void erase(iterator first, iterator last)//删除一段迭代器区间
例:删除一个迭代器位置
set<int> s3;
s3.insert(10);
s3.insert(3);
s3.insert(9);
s3.insert(8);
s3.insert(1);
s3.insert(3);
set<int>::iterator pos = s3.find(10);//当迭代器没找到返回end,end是最后一个数据的下一个
if (pos!=s3.end())
s3.erase(pos);
例:删除一段迭代器区间
set<int> s4;
set<int>::iterator itlow, itup;
for (int i = 1; i<10; i++) s4.insert(i * 10); // 10 20 30 40 50 60 70 80 90
itlow = s4.lower_bound(35);
itup = s4.upper_bound(65);
s4.erase(itlow, itup);
set<int>::iterator it4 = s4.begin();
while (it4 != s4.end())
{
cout << *it4 << " ";
++it4;
}
cout << endl;
1.4 multiset在set的基础上允许键值冗余
例:
multiset<int> s4;
s4.insert(10);
s4.insert(3);
s4.insert(9);
s4.insert(8);
s4.insert(1);
s4.insert(3);
multiset<int>::iterator it4 = s4.begin();
while (it4 != s4.end())
{
cout << *it4 << " ";
++it4;
}
cout << endl;
multiset<int>::iterator pos = s4.find(3);
++pos;
cout << *pos << endl;
if (pos != s4.end())
s4.erase(pos);
it4 = s4.begin();
while (it4 != s4.end())
{
cout << *it4 << " ";
++it4;
}
cout << endl;
运行结果:
2 map和multimap
map和multimap两种头文件都为:#include<map>
map是一种key(键),value(值)的形式,用来保存键和值组成的集合,键必须是唯一的,但值可以不唯一。里面的元素可以根据键进行自动排序,由于map是key_value的形式,所以map里的所有元素都是pair类型。pair里面的first被称为key(键),second被称为value(值)。map的底层是用红黑树来实现的。
在刚开始介绍set的时候,简单介绍了一下pair。现在将pair和make_pair再做一个详细的补充吧
1)pair
pair是将两个数据合成一个数据,当有这样的需求时就要用到pair,就是map。还有一个运用就是函数要返回连个数据的时候要用到pair,pair是一个结构体,因为两个成员变量用的是struct而不是class。
2)make_pair
可以使用pair的构造函数,也可以使用make_ pair来生成我们需要的pair。一般来说,在需要pair的时候我们用make_pair来生成pair的对象很方便,但由于pair可以进行隐式的类型转换局带来一些问题。
template<class K,class V>
inline pair<K, V> make_pair(const K& k,const V& v)
{
return pair<K, V>(k, v);
}
相关操作
例:
map<string, string> dict;
dict.insert(pair<string, string>("sort", "排序"));
dict.insert(pair<string, string>("insert", "插入"));
dict.insert(pair<string, string>("dict", "字典"));
map<string, string>::iterator it1 = dict.begin();
while (it1 != dict.end())
{
//cout << (*it1).first << ":" << (*it1).second << endl;
cout << it1->first << ":" << it1->second << endl;
++it1;
}
map<string, string>::iterator pos= dict.find("insert");
(*pos).second = "XXXXXXXXXXXXX";
2.1 插入insert()
pair<iterator,bool> insert (const value_type& val);//插入一个value_type类型,返回的则是一个pair类型。pair<iterator,bool>就是pair<map<K,V>::iterator,bool>。如果插入成功的话bool值就返回的是true,iterator指向插入的位置,否则的话iterator就指向已经存在的这个元素的位置,iterator是一个pair<K,V>类型的迭代器。
iterator insert (iterator position, const value_type& val);//在一个迭代器的位置插入一个value_type类型,插入成功的话就返回新插入位置的迭代器,否则就返回传入的迭代器。
template <class InputIterator>
void insert (InputIterator first, InputIterator last);//插入的是一段迭代器区间
例:
map<string, string> dict;
dict.insert(pair<string, string>("sort", "排序")); dict.insert(pair<string, string>("insert", "插入"));
dict.insert(pair<string, string>("dict", "字典"));
map<string, string>::iterator it1 = dict.begin();
while (it1 != dict.end())
{
//cout << (*it1).first << ":" << (*it1).second << endl;
cout << it1->first << ":" << it1->second << endl;
++it1;
}
2.2 查找
find()函数
//查找成功的话会返回这个元素的迭代器,否则返回的是end
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
例:
map<string, string> dict;
dict.insert(pair<string, string>("sort", "排序"));
dict.insert(pair<string, string>("insert", "插入"));
dict.insert(pair<string, string>("dict", "字典"));
map<string, string>::iterator pos= dict.find("insert");
(*pos).second = "XXXXXXXXXXXXX";
count()函数
size_type count ( const key_type& x ) const;
和set中的count使用功能相同,count的返回值只有0和1两个值,0表示的是不存在,1表示存在。
2.3 删除
void erase ( iterator position );//删除的是position位置的元素
size_type erase ( const key_type& x );//删除的是键值所在的位置,成功为1,否则为0
void erase ( iterator first, iterator last );//删除一段迭代器区间
例:
map<string, string>::iterator pos= dict.find("insert");
if (pos != dict.end())
{
dict.erase(pos);
}
2.4 operator[]
可以实现修改和插入
mapped_type& operator[] (const key_type& k);
operator[]是很常用的,如果map中有这个key,则它就把这个key所对应的value的引用返回。如果map中没有这个key的话,则它会调用insert(pair< K ,V > (k,V())),将k和V的缺省值对应起来插入后并返回这个value的引用。
其实现如下:
mapped_type& operator[] (const key_type& k)
{
return (*((this->insert(make_pair(k,mapped_type()))).first)).second;
}
例:
string strs[] = { "sort", "sort", "sort", "insert", "insert","second", "left" };
map<string, size_t> countMap;
for (size_t i = 0; i < sizeof(strs) / sizeof(string); ++i)
{
//方法1
map<string, size_t>::iterator it = countMap.find(strs[i]);
if (it != countMap.end())
{
it->second++;
}
else
{
//countMap.insert(pair<string, size_t>(strs[i], 1));
countMap.insert(make_pair(strs[i], 1));
}
//方法2
pair<map<string, size_t>::iterator, bool> ret = countMap.insert(make_pair(strs[i], 1));
if (ret.second == false)
{
ret.first->second++;
}
//方法3
countMap[strs[i]]++;//[]的返回值为value的引用
}
map<string, size_t>::iterator it1 = countMap.begin();
while (it1 != countMap.end())
{
cout << it1->first << ":" << it1->second << endl;
it1++;
}
cout << endl;
运行结果:
例:
map<string, string> dict;
dict["sort"] = "排序";//用[],其中value必须要有缺省的构造函数
dict["insert"] = "字符串";
dict["left"];
dict["left"]="剩余";
dict["left"] = "左边";
dict.insert(make_pair("first", "XXXXXX"));
dict.insert(make_pair("first", "YYYYYYYYYY"));
map<string, string>::iterator it1 = dict.begin();
while (it1 != dict.end())
{
cout << it1->first << ":" << it1->second << endl;
it1++;
}
cout << endl;
3 map和set模拟实现代码
map和set的底层为红黑树,故而要借助红黑树
//RBtree.h
#pragma once
#include<utility>//包含pair类型
enum Colour
{
RED,
BLACK,
};
template<class V>
struct RBTreeNode
{
RBTreeNode<V>* _left;
RBTreeNode<V>* _right;
RBTreeNode<V>* _parent;
V _value;
Colour _col;
RBTreeNode(const V& value = V())
:_value(value)
, _left(NULL)
, _right(NULL)
, _parent(NULL)
, _col(RED)//初始化插入节点的颜色为红色,不影响黑节点个数
{}
};
//迭代器
template<class V, class Ref, class Ptr>
struct _RBTreeIterator
{
typedef RBTreeNode<V> Node;
typedef _RBTreeIterator<V, Ref, Ptr> Self;
Node* _node;
_RBTreeIterator()
{}
_RBTreeIterator(Node* node)
:_node(node)
{}
Ref operator *()
{
return _node->_value;
}
Ptr operator ->()
{
return &(operator *());
}
Self operator ++()
{
if (_node->_right)
{
Node* subleft = _node->_right;
while (subleft->_left)
{
subleft = subleft->_left;
}
_node = subleft;
}
else
{
Node* Parent = _node->_parent;
Node* cur = _node;
while (Parent&&cur == Parent->_right)
{
cur = Parent;
Parent = Parent->_parent;
}
_node = Parent;
}
return *this;
}
Self operator ++(int)
{
Self it(*this);
++(*this);
return it;
}
Self operator --()
{
if (_node->_left)
{
Node* subright = _node->_left;
while (subright->_right)
{
subright = subright->_right;
}
_node = subright;
}
else
{
Node* Parent = _node->_parent;
Node* cur = _node;
while(Parent&&cur == Parent->_left)
{
cur = Parent;
Parent = Parent->_parent;
}
_node = Parent;
}
return *this;
}
Self operator --(int)
{
Self it(*this);
--(*this);
return *this;
}
bool operator !=(const Self& s)
{
return _node != s._node;
}
};
//my_set->rbtree<K,K>
//my_map->rbtree<K,pair<K,V>)
//template<class K, class V>
//class pair
//{
//public:
// pair(const K& key, const V& v)
// :first(key)
// ,second(v)
// {}
//
// const K first;
// V second;
//};
//
//template<class K, class V>
//inline pair<K, V> make_pair(const K& k, const V& v)
//{
// return pair<K, V>(k, v);
//}
template<class K, class V, class KeyOfValue>
struct RBTree
{
typedef RBTreeNode<V> Node;
public:
typedef _RBTreeIterator<V, V&, V*> Iterator;
typedef _RBTreeIterator<V, const V&, const V*> ConstIterator;
RBTree()
:_root(NULL)
{}
Iterator Begin()
{
Node* left = _root;
while (left->_left)
{
left = left->_left;
}
return left;
}
Iterator End()
{
return NULL;
}
std::pair<Iterator,bool> Insert(const V& value)
{
if (_root == NULL)
{
_root = new Node(value);
_root->_col = BLACK;
return make_pair(Iterator(_root),true);
}
KeyOfValue kofv;
Node* parent = NULL;
Node* cur = _root;
while (cur)
{
if (kofv(cur->_value) > kofv(value))//三叉链
{
parent = cur;
cur = cur->_left;
}
else if (kofv(cur->_value) < kofv(value))
{
parent = cur;
cur = cur->_right;
}
else
{
return make_pair(Iterator(cur),false);
}
}
cur = new Node(value);
Node* ret = cur;
if (kofv(parent->_value) < kofv(value))
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
// 调平衡
//检查规则:1.parent为黑,不用调整
//2.parent为红,uncle为红
//3.parent为红,uncle为黑或者不存在
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle&&uncle->_col == RED)//parent为红,uncle为红
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else//parent为红,uncle为黑或者不存在,分单旋和双旋两种情况
{
if (cur == parent->_right)//双旋
{
RotateL(parent);
swap(cur, parent);
}
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle&&uncle->_col == RED)//parent为红,uncle为红
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else//parent为红,uncle为黑或者不存在,分单旋和双旋两种情况
{
if (cur == parent->_left)//双旋
{
RotateR(parent);
swap(cur, parent);
}
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
}
}
_root->_col = BLACK;
return make_pair(Iterator(ret),true);
}
void RotateR(Node* parent)//右旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node* PPnode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
}
else
{
if (PPnode->_left == parent)
{
PPnode->_left = subL;
}
else
{
PPnode->_right = subL;
}
subL->_parent = PPnode;
}
_root->_parent = NULL;
}
void RotateL(Node* parent)//左旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
Node* PPnode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
_root->_parent = NULL;
}
else
{
if (PPnode->_left == parent)
{
PPnode->_left = subR;
subR->_parent = PPnode;
}
else
{
PPnode->_right = subR;
subR->_parent = PPnode;
}
}
}
bool _IsBalance(Node* root, const int & count, int num)
{
if (root->_col == NULL)
return true;
if (root->_col == RED&&root->_parent->_col == RED)//存在两个连续的红节点
return false;
if (root->_col == BLACK)//黑节点就CurBlackNum++
num++;
if (root->_left == NULL&&root->_right == NULL)
{
if (num == count)
{
return true;
}
else
{
return false;//路径上黑节点个数不同返回false
}
}
return _IsBalance(root->_left, count, num) && _IsBalance(root->_right, count, num);
}
bool IsBalance()//是否为红黑树
{
if (_root->_col != BLACK)
{
return false;
}
int count = 0;//统计出一条路径的黑色节点的个数
int num = 0;//需要与count比较的其他路径黑色节点个数
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
count++;
}
cur = cur->_right;
}
return _IsBalance(_root, count, num);
}
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
// cout << kofv(root->_value) << " ";
_InOrder(root->_right);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
Iterator Find(const K& key)
{
KeyOfValue kofv;
Node* cur = _root;
while (cur)
{
if (kofv(cur->_value) > key)//三叉链
{
cur = cur->_left;
}
else if (kofv(cur->_value) < key)
{
cur = cur->_right;
}
else
{
return Iterator(cur);
}
}
return End();
}
private:
Node* _root;
};
struct SetKeyOfValue
{
const int& operator()(const int& key)
{
return key;
}
};
//Myset.h
#pragma once
#include"RBtree.h"
#include<utility>//包含pair类型
#include<string>
template<typename K>
class Set
{
public:
struct SetKeyOfValue
{
const K& operator()(const K& key)
{
return key;
}
};
typedef typename RBTree<K, K, SetKeyOfValue>::Iterator Iterator;
std::pair<Iterator, bool> Insert(const K& key)
{
return _t.Insert(key);
}
Iterator Find(const K& key)
{
return _t.Find(key);
}
Iterator Begin()
{
return _t.Begin();
}
Iterator End()
{
return _t.End();
}
protected:
RBTree<K, K, SetKeyOfValue> _t;
};
//Mymap.h
#pragma once
#include<utility>//包含pair类型
#include"RBtree.h"
#include<string>
template<class K, class V>
class Map
{
public:
struct MapKeyOfValue
{
const K& operator()(const std::pair<K, V>& kv)
{
return kv.first;
}
};
typedef typename RBTree<K, std::pair<K, V>, MapKeyOfValue>::Iterator Iterator;
std::pair<Iterator, bool> Insert(std::pair<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;
}
Iterator Find(const K& key)
{
return _t.Find(key);
}
Iterator Begin()
{
return _t.Begin();
}
Iterator End()
{
return _t.End();
}
protected:
RBTree<K, std::pair<K, V>, MapKeyOfValue> _t;
};
//test.cpp
#include<utility>//包含pair类型
#include"RBtree.h"
#include"Mymap.h"
#include"Myset.h"
#include<iostream>
#include"Windows.h"
using namespace std;
void TestRBTree()
{
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
RBTree<int, int, SetKeyOfValue> t;
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
t.Insert(a[i]);
}
RBTree<int, int, SetKeyOfValue>::Iterator it = t.Begin();
while (it != t.End())
{
cout << *it << " ";
it++;
}
cout << endl;
it = t.Begin();
++it;
++it;
++it;
--it;
--it;
cout << *it << endl;
}
void TestMySet()
{
Set<string> s;
s.Insert("sort");
s.Insert("insert");
s.Insert("set");
s.Insert("map");
s.Insert("iterator");
s.Insert("value");
s.Insert("value");
Set<string>::Iterator it1 = s.Begin();
while (it1 != s.End())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
}
void TestMyMap()
{
Map<string, string> dict;
dict.Insert(pair<string, string>("left", "左边"));
dict.Insert(pair<string, string>("dict", "字典"));
dict.Insert(pair<string, string>("Insert", "字符串"));
dict.Insert(pair<string, string>("map", "映射"));
dict.Insert(pair<string, string>("left", "剩余"));
dict["left"] = "剩余";
dict["set"] = "集合";
Map<string, string>::Iterator it = dict.Begin();
while (it != dict.End())
{
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
int main()
{
TestRBTree();
TestMySet();
TestMyMap();
system("pause");
return 0;
}
运行结果如下: