关联式容器—set、multiset、map、multimap知识点总览
1.关联式容器:
底层实现使用红黑树。初始化、遍历、查找(count,find)、插入(insert)(set与map需要判断插入是不是成功),自定义类型需要去对Compare进行改写(std::less、std::greater、函数对象)。
2.set
1、不能存放关键字key相同的元素,关键字必须唯一
2、默认以升序进行排列
3、底层实现是红黑树--不支持进行数据修改,不支持下标访问
4.std::greater<int>,std::less<int>,自定义排序仿函数书写
5.insert成功返回true或者false,ret.second,pair的第二个参数红黑树的五大特征:
1、节点不是红色就是黑色
2、根节点是黑色的
3、叶子节点也是黑色的
4、如果一个节点是红色的,那么它的左右孩子节点必须是黑色的
5、从根节点到叶子节点上所有路径要保证黑色节点的个数相同
3.multiset
1、可以存放关键字key相同的元素,关键字不唯一
2、默认以升序进行排列
3、底层实现是红黑树
4.与set的区别,insert进行插入数据肯定是成功的,没有返回值
4.map
1、存放的是键值对,也就是也个pair,即pair<const Key, value>,key值必须唯一,不能重复
2、默认按照关键字key进行升序排列
3、底层实现是红黑树查找:
auto it = numbers.lower_bound(2);//>=key的第一个位置
auto it2 = numbers.upper_bound(2);//>key的第一个位置
5.mutilmap
1、可以存放关键字key相同的元素,关键字不唯一
2、默认以升序进行排列
3、底层实现是红黑树
4、与map的区别:关键字不唯一,进行插入的时候,肯定是成功的
6.insert参考接口
1.value_type,若是set/multiset代表的是key,
若是map/multimap代表的是pair<const key, value>std::pair<iterator,bool>2.insert( const value_type& value ); //插入左值
std::pair<iterator,bool>
3.insert( value_type&& value );iterator//插入右值
4.insert( iterator hint, const value_type& value );//获取某个位置的迭代器,往那个位置进行插入
5.iterator insert( const_iterator hint, const value_type& value );
6.iterator insert( const_iterator hint, value_type&& value );
7.template< class InputIt > void insert( InputIt first, InputIt last );
8.void insert( std::initializer_list<value_type> ilist );//插入列表
9.insert_return_type insert(node_type&& nh);
10.iterator insert(const_iterator hint, node_type&& nh);
set案例
1.set查找元素find,如果元素在set中存在,返回该元素的迭代器,否则返回 set.end()
2.set容器插入操作insert
2.1 insert的返回结果是一对pair,first是当前插入值在set中的位置迭代器,second代表插入是否成功
2.2 以列表的形式往set中插入数据:两种方式(迭代器范围和大列表方式)返回的都是void
3.set的删除erase: 1.按迭代器位置删除 2.按迭代器范围进行删除(左闭右开
3.返回值是被删除的最后一个元素对应的迭代器。
4.set不允许使用下标操作,为了保护红黑树的结构稳定,迭代器内容不允许修改,*it=20-->错误
#include <math.h>
#include <iostream>
#include <set>
#include <utility>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using std::ostream_iterator;
using std::cout;
using std::endl;
using std::set;
using std::pair;
using std::string;
using std::vector;
template <typename Container>
void display(const Container &con)
{
for(auto &elem : con)
{
cout << elem << " ";
}
cout << endl;
}
void test01()
{
set<int> number = {1,3,5,7,9,11,13,7,8,10,1};
display(number);//1 3 5 7 8 9 10 11 13
cout<<"1.set查找元素find:"<<endl;
auto it = number.find(3);//如果元素在set中存在,返回该元素的迭代器
if(it == number.end())
{
cout<<"该元素不在set中"<<endl;
}
else
{
cout<<"该元素在set中"<<endl;
}
cout<<"2.set容器插入操作insert:"<<endl;
//insert的返回结果是一对pair,first是当前插入值在set中的位置迭代器,第二个代表插入是否成功
pair<set<int>::iterator, bool> ret = number.insert(2);
if(ret.second == true)
{
cout<<"插入元素成功"<<*ret.first<<endl;
cout<<ret.second<<endl;
}
else
{
cout<<"该元素在set中存在,插入失败"<<endl;
cout<<*ret.first<<endl;//10
cout<<ret.second<<endl;//0
}
//first是2在set中的对应的迭代器
copy(ret.first,number.end(),ostream_iterator<int>(cout," "));
//2 3 5 7 8 9 10 11 13
cout<<endl;
cout<<"3.以列表的形式往set中插入数据:两种方式返回的都是void"<<endl;
cout<<"3.1迭代器形式插入:"<<endl;
vector<int> vec = {10,20,30};
number.insert(vec.begin(),vec.end());
display(number);//1 2 3 5 7 8 9 10 11 13 20 30
cout<<"3.2大括号形式进行插入"<<endl;
number.insert(std::initializer_list<int>({-9,100,200,300}));
//display(number);
copy(number.begin(),number.end(),ostream_iterator<int>(cout," "));//输出迭代器方式进行输出
//-9 1 2 3 5 7 8 9 10 11 13 20 30 100 200 300
cout<<endl;
cout<<"4.set的删除erase:1.按迭代器位置删除 2.按范围进行删除:"<<endl;
cout<<"4.1按迭代器位置进行删除"<<endl;
it = number.begin();//-9
it++;//1
it++;//2,set里面的迭代器用的BidirectionalIterator双向迭代器,可进行++,--
it++;//3
it--;//2
number.erase(it);//按迭代器位置删除,删除第二个迭代器,对应的值为2
display(number);//-9 1 3 5 7 8 9 10 11 13 20 30 100 200 300
cout<<"4.2按照迭代器范围进行删除:左闭右开"<<endl;
it=number.begin();
for(int idx = 0;idx<5;idx++)
{
++it;
}
cout<<*it<<endl;//8
number.erase(number.begin(),it);//左闭右开
display(number);//8 9 10 11 13 20 30 100 200 300
}
int main()
{
test01();
return 0;
}
/*
1 3 5 7 8 9 10 11 13
1.set查找元素find:
该元素在set中
2.set容器插入操作insert:
插入元素成功2
1
2 3 5 7 8 9 10 11 13
3.以列表的形式往set中插入数据:两种方式返回的都是void
3.1迭代器形式插入:
1 2 3 5 7 8 9 10 11 13 20 30
3.2大括号形式进行插入
-9 1 2 3 5 7 8 9 10 11 13 20 30 100 200 300
4.set的删除erase:1.按迭代器位置删除 2.按范围进行删除:
4.1按迭代器位置进行删除
-9 1 3 5 7 8 9 10 11 13 20 30 100 200 300
4.2按照迭代器范围进行删除:
8
8 9 10 11 13 20 30 100 200 300
*/
set容器实现自定义类型存储---重写Compare函数
自定义类型Point
class Point
{
public:
Point(int ix=0,int iy=0)
:_ix(ix),_iy(iy)
{
}
float getDistance()const
{
return hypot(_ix,_iy);//两个数平方和再开方,求坐标距O的距离
}
~Point()
{
}
//重载左移运算符,直接实现打印对象
friend std::ostream &operator<<(std::ostream &os,const Point &rhs);
friend bool operator<(const Point &lhs,const Point &rhs);
//friend bool operator>(const Point &lhs,const Point &rhs);
friend struct CompareSet;//函数对象
private:
int _ix;
int _iy;
};
std::ostream& operator<<(std::ostream &os,const Point &rhs)
{
os << "(" << rhs._ix
<< ", " << rhs._iy
<< ")";
return os;
}
bool operator<(const Point &lhs,const Point &rhs)
{
if(lhs.getDistance() < rhs.getDistance())
{
return true;
}
else if(lhs.getDistance() == rhs.getDistance())//相等的情况,需要分类讨论
{
if(lhs._ix < rhs._ix)
{
return true;
}
else if(lhs._ix == rhs._ix)
{
if(lhs._iy < rhs._iy)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else//lhs.getDistance() > rhs.getDistance()
{
return false;
}
}
//函数对象
struct CompareSet
{
bool operator()(const Point &lhs,const Point &rhs)const
{
if(lhs.getDistance() < rhs.getDistance())
{
return true;
}
else if(lhs.getDistance() == rhs.getDistance())//相等的情况,需要分类讨论
{
if(lhs._ix < rhs._ix)
{
return true;
}
else if(lhs._ix == rhs._ix)
{
if(lhs._iy < rhs._iy)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else//lhs.getDistance() > rhs.getDistance()
{
return false;
}
}
};
//对于自定义类型,set的使用
void test02()
{
Point p1(3,4);
cout<<p1.getDistance()<<endl;
cout<<p1<<endl;
set<Point,std::less<Point>> point={
Point(1,2),
Point(-1,-2),
Point(3,2),
Point(2,4),
Point(3,5)
} ;
// set<Point,CompareSet> point={
// Point(1,2),
// Point(-1,-2),
// Point(3,2),
// Point(2,4),
// Point(3,5)
// } ;
display(point);
}
/*test02运行结果:
5
(3, 4)
(-1, -2) (1, 2) (3, 2) (2, 4) (3, 5)
*/
set容器存储自定义类型Person
class Person
{
public:
Person(int num=0, string name="hello world")
:_num(num),_name(name)
{
}
friend bool operator<(const Person &lhs,const Person &rhs);
friend std::ostream& operator<<(std::ostream &os,const Person &rhs);
friend struct MyPersonSet;//函数对象形式
private:
int _num;
string _name;
};
bool operator<(const Person &lhs,const Person &rhs)
{
if(lhs._num != rhs._num)
{
return lhs._num < rhs._num;
}
else
{
return lhs._name!=rhs._name;
}
}
std::ostream& operator<<(std::ostream &os,const Person &rhs)
{
os<<rhs._num<<":"<<rhs._name;
return os;
}
struct MyPersonSet
{
bool operator()(const Person &lhs, const Person &rhs)
{
if(lhs._num != rhs._num)
{
return lhs._num < rhs._num;
}
else
{
return lhs._name!=rhs._name;
}
}
};
//set自定义类型
void test03()
{
set<Person,std::less<Person>> person = {//在自定义类Person里面重载<运算符
Person(1,"孙悟空"),
Person(2,"白龙马"),
Person(3,"沙 僧"),
Person(3,"唐 僧"),
Person(6,"猪八戒"),
Person(9,"白骨精"),
Person(1,"孙悟空"),
Person(9,"白骨精")
};
display(person);
}
/*
1:孙悟空 2:白龙马 3:唐 僧 3:沙 僧 6:猪八戒 9:白骨精
*/
//函数对象形式
void test04()
{
set<Person,MyPersonSet> person = {
Person(1,"孙悟空"),
Person(2,"白龙马"),
Person(3,"沙 僧"),
Person(3,"唐 僧"),
Person(6,"猪八戒"),
Person(9,"白骨精"),
Person(1,"孙悟空"),
Person(9,"白骨精")
};
display(person);
}
/*
1:孙悟空 2:白龙马 3:唐 僧 3:沙 僧 6:猪八戒 9:白骨精
*/
map案例代码
1.map容器的操作和set大多相同
2.map允许用下标进行访问,如果被访问的key值不存在,会自动把key加入容器,有默认值
#include <iostream>
#include <math.h>
#include <iostream>
#include <map>
#include <utility>
#include <string>
using std::cout;
using std::endl;
using std::map;
using std::pair;
using std::string;
template <typename Container>
void display(const Container &con)
{
for(auto &elem : con)
{
cout << elem.first << " " << elem.second << endl;
}
}
void test01()
{
map<string, string> number={
{"021", "北京"},
{"027", "武汉"},
{"0755", "深圳"},
{"022", "天津"},
pair<string, string>("0653", "北京"),
pair<string, string>("021", "南京"),
std::make_pair("0712", "广州"),
std::make_pair("022", "广州")
};
cout<<"1.map的插入操作:"<<endl;
auto ret = number.insert(pair<string,string>("999", "苏州"));
if(ret.second)
{
cout << "该元素不在map中,插入成功 "
<< ret.first->first << " "
<< ret.first->second << endl;
}
else
{
cout << "该元素存在,map中, 插入失败" << endl;
}
display(number);
cout<<"2.map的下标访问操作:"<<endl;
cout << "number[\"1\"] = " << number["022"] << endl;
cout << "number[\"10\"] = " << number["10"] << endl;
display(number);
}
int main()
{
test01();
return 0;
}