目录
容器自定义排序
map< int, int >
set< int, int >
priority_queue< pair< int, int >>
仿函数见正文或者下面的链接,定义一个类,重载()
仿函数
- 注意
lambda函数
没有type
,是匿名的仿函数,因此我们需要用decltype
来自动生成这个对象. - 使用
lambda
表达式需要在q
对象构造的时候,将lambda表达式作为参数传入其中。即q(cmp) - 容器中排序加的是
class _pr type
;sort
中加的是_Pr
因此sort里面可以直接传入bool函数
lambda
方法:
typedef struct MyStudent{
std::string name;
int grade;
} Student;
//Lambda设置map排序规则,同样适合于set
auto func = [](const Student* left, const Student* right)
{
return left->grade < right->grade;
};
//定义map
std::map<const Student*, std::string, decltype(func)> stuMap(func);
//定义set
std::set<const Student*, decltype(func)> stuSet(func);
auto compfun = [](pair<int, int>& a, pair<int, int>& b)->bool {
return a.second > b.second;
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(compfun)> q(compfun);
由于在类里面不能用auto方法,所以可选择class方式实现自定义排序
class {public: operator()(){}};
class KthLargest {
public:
class sor {
public:
bool operator()(pair<int, int>& a, pair<int, int>& b) {
return a.second > b.second;
}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(sor)> q2;
};
decltype
方法:
不加引号,表示decltype(fa)是一个函数
加引号,表示decltype(fa)是一个函数指针,则fa必须为static才能找到
unorder_map<自定义key,value>
当 C++ Standard 没有为当前 Key 提供hash函数时,需要手动构建。
以pair<int, int>
为例
class ListNode;
struct pair_hash
{
template<class T1, class T2>
std::size_t operator() (const std::pair<T1, T2>& p) const
{
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
return h1 ^ h2;
}
};
unordered_map<pair<ListNode *, bool>, int, pair_hash> pairMap;
1、string容器
1.1 string基本概念
本质:
- string是C++风格的字符串,而string本质上是一个类
string和char*的区别:
- char*是一个指针
- string是一个类,类内部封装了char*,管理这个字符串,是一个char型的容器
特点:
string类内部封装了很多成员方法
e.g. 查找find,拷贝copy,删除delete,替换replace,插入insert
string管理char所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
1.2 string构造函数
构造函数原型:
string();
//创建一个空的字符串
string(const char* s);
//使用字符串s初始化string(const string& str))
//使用一个string对象初始化另一个string对象string(int n, char c);
//使用n个字符c初始化
void test02()
{
string s1; // default construct
const char* str = "hello world";
string s2(str); //使用字符串s初始化
cout << "s2=" << s2 << endl;
string s3(s2); // 拷贝构造
cout << "s3=" << s3 << endl;
string s4(10, 'a'); //使用n个字符c初始化
cout << "s4=" << s4 << endl;
}
1.3 string赋值操作
功能描述
- 给string字符串进行幅值
赋值的函数原型:
string& operator=(const char* s);
//char* 类型字符串 赋值给 当前的字符串string& operator=(const string& s);
//把字符串s 赋值给 当前的字符串string& operator=(char c);
//字符 赋值给 当前的字符串string& assign(const char* s)
//把字符串s 赋值给 当前的字符串string& assign(const string& s);
//把字符串s 赋值给 当前的字符串string& assign(const char* s, int n);
//把字符串s的前n个字符 赋值给 当前的字符串string& assign(int n, char c);
//用n个字符c 赋值给 当前的字符串
// 例如:
void test03()
{
string str1;
str1 = "hello world";
cout << "str1=" << str1 << endl;
}
1.4 string字符串拼接
功能描述
- 实现再字符串末尾拼接字符串
函数原型
string& operator+=(const char* str);
// 重载+=操作符string& operator+=(const char c);
string& operator+=(const string& str);
string& append(const char* s)
//把字符串s 连接到 当前的字符串结尾string& append(const string& s);
//把字符串s 连接到 当前的字符串结尾string& append(const char* s, int n);
//把字符串s的前n个字符 连接到 当前的字符串结尾string& append(const string& s, int pos, int n);
//字符串s中从pos开始的n个字符连接到字符串结尾
void test04()
{
string str3 = "I";
string str2 = "LOL DNF";
str3.append(" love ");
str3.append("game abcde", 5);
str3.append(str2, 4, 3); //从第5个位置(D)开始截取3个字符数
cout << "str3 = " << str3 << endl; //I love game DNF
}
1.5 string查找和替换
功能描述:
- 查找:查找指定字符串是否存在,返回位置;若没有,则返回-1
- 替换:再指定的位置替换字符串
函数原型Function prototype
int find(const string& str, int pos = 0) const;
//查找str第一次出现的位置,从pos开始查找,返回位置int find(const char* s, int pos = 0) const;
//查找s第一次出现的位置,从pos开始查找int find(const char* s, int pos, int n) const;
//从pos位置查找s的前n个字符第一次位置int find(const char c, int pos = 0) const;
//查找字符c第一次出现的位置int rfind(const string& str, int pos = npos) const;
//查找str最后一出现的位置,从pos开始查找int rfind(const char* s, int pos = npos) const;
//查找s最后一出现的位置,从pos开始查找int rfind(const char c, int pos = 0) const;
//查找字符c最后一次出现的位置string& replace(int pos, int n, const string& str);
//替换从pos开始的n个字符为字符串strstring& replace(int pos, int n, const char* s);
//替换从pos开始的n个字符为字符串s
1.6 string字符串比较
功能描述
- 字符串之间的比较
比较方式:
- 字符串比较是按字符的ASCII码进行对比
若=,返回0
若>,返回1
若<,返回-1
函数原型
int compare(const string& s) const;
int compare(const char* s) const;
1.7 string字符存取
string中单个字符存取方式有两种(两者等价,可读可写)
char& operator[](int n );
//通过[ ]方式取字符char& at(int n);
//通过at方法获取字符
1.8 string插入和删除
功能描述:
- 对string字符串进行插入和删除字符操作
函数原型:
string& insert(int pos, const char* s);
//插入字符串string& insert(int pos, const string& str);
//插入字符串string& insert(int pos, int n, char c);
//在指定位置插入n个字符cstring& erase(int pos, int n = npos);
//删除从Pos开始的n个字符
void test01()
{
string str = "hello";
str.erase(1, 3); //从第一个位置起,删除3个字符。str=="h"
}
1.9 string 字串
功能描述:
- 从字符串中获取想要的子串
函数原型
string substr(int pos = 0, int n = npos) const;
//返回由pos开始的n个字符组成的字符串
2 vector容器
2.1 vector基本概念
功能:
- vector数据结构和数组非常相似,也成为单端数组
vector与普通数组的区别:
- 不同之处在于数组是静态空间加粗样式,而vector可以动态扩展
【注】动态扩展:
并不是在原空间后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间。
vector容器的迭代器是支持随机访问的迭代器(跳跃访问,如v.begin() + 3等等)
2.2 vector构造函数
函数原型:
vector<T> v;
//采用模板实现类实现,default construct functionvector(v.begin(), v.end());
//将v[begin(), end()]区间中的元素拷贝给本身vector(n, elm);
//构造函数将n个elm拷贝给本身vector(const vector& vec);
//拷贝构造函数
void printVector(vector <int>& v)
{
for(vector<int>::iterator it=v.begin(); it!=v.end(); it++)
{
cout<<*it<<" ";
cout<<endl;
}
}
void test01()
{
vector<int>v1; // 默认构造
for (int i = -; i<10; i++)
{
v1.push_back(i);
}
printVector(v1);
//通过区间方式进行构造
vector<int>v2(v1.begin(), v1.end()):
//n个element的方式进行构造
vector<int>v3(10, 100); //10个100
//拷贝构造
vector<int>v4(v3);
}
2.3 vector 幅值操作
函数原型:
vector& operator=(const vector &vec);
//重载等号操作符assign(begin, end);
//将[begin, end]区间中的数据拷贝幅值给本身assign(n, elm);
//将n个elem拷贝幅值给本身
2.4 vector 容量和大小
函数原型:
empty();
//判断函数是否为空capacity();
//容器的容量(永远大于等于size())size();
//返回容器中元素的个数resize(int num);
//重新指定容器的长度为num,若容器变长,则以默认值0填充新位置; 如果容器变短,则末尾超出容器长度的元素将被删除。resize(int num, elem)
//重新指定容器的长度为num,若容器变长,则以elem填充新位置; 如果容器变短,则末尾超出容器长度的元素将被删除。
【注】resize不改变容量大小
void printVector(vector <int>& v)
{
for(vector<int>::iterator it=v.begin(); it!=v.end(); it++)
{
cout<<*it<<" ";
cout<<endl;
}
}
void test01()
{
vector <int> v1;
for (int i = 0; i<10; i++)
{
v1.push_back(i);
}
printVector(v1);
cout << "v1的容量为" << v1.capacity() << endl;
//例如:v1的容量为13,此时已占用10个数,还能放3个数。如果超过容器则重新划出一个更大的容器幅值
cout << "v1的大小d为" << v1.size() << endl; //size 等于10
}
2.5 vector插入和删除
函数原型
push_back(ele);
//尾部插入一个元素pop_back();
//删除最后一个元素insert(const_iterator pos, ele);
//迭代器指向位置pos插入元素ele, 【注】const_iterator 是只读迭代器insert(const_iterator pos, int count, ele
//迭代器指向位置pos插入count个元素eleerase(const_iterator pos);
//删除迭代器指向的元素erase(const_iterator start, const_iterator end);
//删除迭代器从start到end之间的元素clear();
//删除容器中所有元素
2.6 vector数据存取
函数原型
at(int idx);
//返回索引idx所指的数据operator[];
//重载操作符[ ], 返回索引idx所致的数据front();
//返回容器中第一个数据元素back();
//返回容器中最后一个数据元素
2.7 vector互换容器
函数原型:
swap(vec);
//将vec与本身的元素互换
void printVector(vector <int>& v)
{
for(vector<int>::iterator it=v.begin(); it!=v.end(); it++)
{
cout<<*it<<" ";
cout<<endl;
}
}
void test01()
{
vector <int> v1;
for (int i = 0; i<10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector <int> v2;
for (int i = 10; i>0; i--)
{
v2.push_back(i);
}
printVector(v2);
v1.swap(v2);
printVector(v1);
printVector(v2);
}
实际用途:
- 收缩内存空间
void test02()
{
vector <int> v;
for (int i = 0; i<10000; i++)
{
v.push_back(i);
}
cout << "v的容量为" << v.capacity() << endl;
//例如:v的容量为13880,size为10000
cout << "v的大小d为" << v.size() << endl;
v.resize(3);
cout << "v的容量为" << v.capacity() << endl;
//此时 v的容量为13880,size为3
cout << "v的大小d为" << v.size() << endl;
vector <int> (v).swap(v);
// vector <int> (v) 为匿名对象,按照当前v所用的元素来初始化容器大小,
// 且匿名对象用完就会被删除
cout << "v的容量为" << v.capacity() << endl;
//此时,v的容量为3,size为3
cout << "v的大小d为" << v.size() << endl;
}
2.8 vector预留空间
功能描述:
- 减少vector在动态扩展容量时的扩展次数
函数原型:
reserve(int len);
//容器预留len个元素长度,预留位置不初始化,元素不可访问
void test01()
{
vector <int> v;
//v.reserve(100000) //直接告诉编译器,为v开辟100000int的内存空间
int num = 0; //统计为v的内存空间开辟的次数
int* p = NULL;
for (int i = 0; i<100000; i++)
{
v.push_back(i);
if (p != &v[0]) //每次当v的容量不够时,v开辟新的内存,&v[0]会更换地址
{
p = &v[0];
num++;
}
}
cout << "num=" << num << endl;
}
3 list容器
3.1 list基本概念
功能: 将数据进行链式存储
链表(list) 是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。
链表的组成:链表由一系列结点 组成
结点的组成:一个是存储数据元素的数据域 ,另一个是存储下一个节点地址的指针域
STL中的链表是一个双向循环列表
(双向:每个结点都存了前后两个结点的地址;循环:首尾相接。【注】图示不是循环结构)
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器
list的优点:
- 采用动态存储分配,不会造成内存浪费和溢出
- 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
- 链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大
list有一个重要的性质,插入和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的(因为vector需要扩容时,会找一块新的内存空间,原有迭代器指向就会失效)
3.2 list构造函数
函数原型:
list<T> lst;
//采用模板实现类实现,default construct functionlist(lst.begin(), lst.end());
//将lst[begin(), end()]区间中的元素拷贝给本身list(n, elm);
//构造函数将n个elm拷贝给本身list(const list& lst);
//拷贝构造函数
3.3 list 幅值和交换
函数原型:
list& operator=(const list& lst);
//重载等号操作符assign(begin, end);
//将[begin, end]区间中的数据拷贝幅值给本身assign(n, elm);
//将n个elem拷贝幅值给本身swap(lst);
//将lst与本身的元素互换
3.4 list大小操作
函数原型:
empty();
//判断容器是否为空size();
//返回容器中元素的个数resize(int num);
//重新指定容器的长度为num,若容器变长,则以默认值0填充新位置; 如果容器变短,则末尾超出容器长度的元素将被删除。resize(int num, elem)
//重新指定容器的长度为num,若容器变长,则以elem填充新位置; 如果容器变短,则末尾超出容器长度的元素将被删除。
3.5 list插入和删除
函数原型
push_back(ele);
//尾部插入一个元素pop_back();
//删除最后一个元素push_front(elem);
//在容器开头插入一个元素pop_front();
//删除第一个元素insert(const_iterator pos, elem);
//迭代器指向位置pos插入元素elem, 【注】const_iterator 是只读迭代器insert(const_iterator pos, int count, elem
//迭代器指向位置pos插入count个元素eleminsert(pos, begin, end);
//在pos位置插入[begin, end)区间的数据,无返回值erase(const_iterator pos);
//删除迭代器指向的元素erase(const_iterator start, const_iterator end);
//删除迭代器从start到end之间的元素clear();
//删除容器中所有元素remove(elem);
//删除容器中所有与elem值匹配(一样)的元素
void printList(const list <int>& l)
{
for (list <int> const_iterator::it = l.begin(); it!=l.end(); it++)
{
cout << *it << ' ' << endl;
}
}
void test01()
{
list<int> L;
L.push_back(10);
L.push_back(20);
L.push_front(900);
L.push_front(800);
list <int>::iterator it = L.begin()
L.insert(++it, 100); // 800 100 900 10 20
}
3.6 list数据存取
函数原型
front();
//返回第一个元素back();
void test01()
{
list<int> L;
L.push_back(10);
L.push_back(20);
L.push_front(900);
L.push_front(800);
//L[0] ❌ 不可以用[]访问list容器中的元素
//L.at(0) ❌ 不可以用at方式访问
// 因为list不是连续线性空间存储数据,迭代器
cout << L.front() << endl;
list <int>::iterator it = L.begin()
//it = it + 1 ❌ 不支持+1, +2这样的随机访问
it++;
it--;// 只能一个一个移动(双向移动)
}
3.7 list反转和排序
函数原型:
reverse();
//反转链表 [1, 4, 5, 3, 9] => [9, 3, 5, 4, 1]sort();
//链表排序
【注】所有不支持随机访问迭代器的容器,不可以用标准算法#inclue<algorithm>
如错误案例(假设L1为某链表)//sort(L1.begin(), L1.end()); ❌
。因此这两个函数是类内部成员函数提供的算法,正确案例L1.sort();
L1.reverse();
4 deque容器
4.1 deque容器基本概念
功能:
- 双端数组,可以对头端进行插入删除操作
deque与vector的区别:
- vector对于头部的插入删除效率低,数据量越大,效率越低
- deque相对而言,对头部的插入删除速度比vector快
- vector访问元素时的速度比deque快,这与二者的内部实现有关
deque内部工作原理
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
图注: - 0x01指向的是头部缓冲区地址,0x03指向的是尾部缓冲区地址。
- 当头部与尾部需要增删数据时,就可通过中控器找到对应地址,进行push or pop。
- 当头/尾部缓冲区内存不够时,中控器再给出一个新地址对应的新的头/尾部缓冲区。
4.2 deque构造函数
函数原型:
deque <T> deqT;
//默认构造形式deque(begin, end);
//构造函数将[begin, end]区间中的元素拷贝给本身deque(n, elem);
//构造函数将n个elem拷贝给本身deque(const deque &deq);
//拷贝构造函数
4.3 deque赋值操作
函数原型:
deque& operator = (const deque& deq);
//重载等号操作符assign(begin, end);
//将[begin, end)区间中的数据拷贝赋值给本身assign(n, elem);
//将n个elem拷贝赋值给本身
4.4 deque大小操作
函数原型:
deque.empty();
//判断容器是否为空deque.size();
//返回容器中元素的个数deque.resize (num);
//重新指定容器的长度为num,若容器变长,则以默认值0填充新位置;若容器变短,则末尾超出容器长度的元素被删除deque.resize(num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置;若容器变短,则末尾超出容器长度的元素被删除
4.5 deque插入和删除
函数原型:
两端插入操作:
push_back(elem);
//在容器尾部添加一个数据push_front(elem);
//在容器头部插入一个数据pop_back();
//删除容器最后一个数据pop_front();
//删除容器第一个数据
指定位置操作:
insert(pos, elem);
//在pos位置插入一个elem元素的拷贝,返回新数据的位置insert(pos, n, elem);
//在pos位置插入n个elem数据,无返回值insert(pos, begin, end);
//在pos位置插入[begin, end)区间的数据,无返回值clear();
//清空容器的所有数据erase(begin, end);
//删除[begin, end)区间的数据,返回下一个数据的位置erase(pos);
//删除pos位置的数据,返回下一个数据的位置
void test01()
{
deque <int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(30);
deque <int> d2;
d2.push_back(1);
d2.push_back(2);
d2.push_back(3);
//区间插入
d1.insert(d1.begin(), d2.begin(), de.end());
}
4.6 deque 数据存取
函数原型:
ar(int idx);
//返回索引idx所指的数据operator[];
//返回索引idx所指的数据front();
//返回容器中第一个数据元素back();
//返回容器中最后一个数据元素
4.7 deque排序
算法
sort(iterator begin, iterator end)
//对beg和end区间内元素进行排序(默认从小到大的升序)
【注】对于支持随机访问的迭代器的容器,都可以利用sort算法进行排序,如vector
5 stack容器
5.1 stack基本概念
stack是一种先进后出(First in Last out, FILO) 的数据结构,它只有一个出口。栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为。
5.2 stack常用接口
构造函数:
stack <T> stk;
//stack采用模板类实现,stack对象的默认构造形式stack(const stack &stk);
//拷贝构造函数
赋值操作:
stack& operator=(const stack &stk);
//重载等号操作符
数据存取:
push(elem);
//向栈顶添加元素pop();
//从栈顶移除第一个元素top();
//返回栈顶元素
大小操作
empty();
//判断堆栈是否为空size();
//返回栈的大小
6 queue容器
6.1 queue的基本概念
队列是一种先进先出(First in First Out, FIFO) 的数据结构,它有两个出口(吃多了拉出来是queue,吃多了吐出去是stack)
队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头和队尾可以被外界使用,因此队列不允许有遍历行为
队列中进数据——入队,push
6.2 queue常用接口
构造函数
queue <T> que;
//queue采用模板类实现,queue对象的默认构造形式queue(const queue& que);
//拷贝构造函数
赋值操作
queue& operator=(const queue& que);
//重载等号操作符
数据存取
push(elem);
//往队尾pop();
//从队头移除第一个元素back();
//返回最后一个元素front();
//返回第一个元素
大小操作
empty();
//判断堆栈是否为空size();
//返回栈的大小
7 set/multiset 容器
7.1 set基本概念
所有元素都会在插入时,自动被排序
本质: set/multiset 属于关联式容器,底层结构使用二叉树 实现。
set和multiset的区别:
- set不允许容器中有重复的元素
- multiset允许容器中有重复的元素
7.2 set构造和赋值
功能描述:创建set容器以及赋值
构造
set <T> st;
//默认构造函数set(const set& st);
//拷贝构造函数
赋值:
set& operator=(const set& st);
//重载等号操作符
7.3 set插入与删除
函数原型:
insert(elem);
//在容器中插入元素clear();
//清楚所有元素erase(pos);
//删除pos迭代器所指的元素,返回下一个元素的迭代器erase(begin, end);
//删除区间[begin, end)的所有元素,返回下一个元素的迭代器erase(elem);
//删除容器中值为elem的元素
7.4 set大小和交换
函数原型:
size();
//返回容器中元素的数目empty();
//判断容器是否为空swap(st);
//交换两个集合容器
7.5 set查找和统计
函数原型:
find(key);
//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();count(key);
//统计key的元素个数
7.6 set和multiset区别
- set不可以插入重复数据,multiset可以
- set插入数据的同时会返回插入结果,表明插入是否成功(
pair<iterator, bool>
,表明插在哪儿,插入成功结果) - multiset不会检测数据,因此可以插入重复数据
void test01()
{
set <int> s;
pair <set<int>::iterator, bool> ret = s.insert(10);
if(ret.second) //第一次插入成功
{
cout << "第一次插入成功" << endl;
}else
{ cout << "第一次插入失败" << endl;
}
ret = s.insert(10);
if(ret.second) //第二次插入失败, 不能重复插入
{
cout << "第二次插入成功" << endl;
}else
{ cout << "第二次插入失败" << endl;
}
}
7.7 pair对组创建
功能描述:
成对出现的数据,利用对组可以返回两个数据
两种创建方式:
pair <type, type> p (value1, value2);
//类似于默认构造pair <type, type> p = make_pair(value1, value2);
void test01()
{
pair<string, int>p("Tom", 20);
cout << "姓名:" << p.first << "年龄:" << endl;
}
7.8 set容器排序
默认排序为从小到大。利用仿函数,可以改变排序规则
示例一:存放内置数据类型
void printSet(set<int>& s)
{
for (set<int>::iterator it=s.begin(); it!=s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
class MyCompare // 仿函数 bool类型
{
public:
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
};
void test01()
{
set <int> s1;
s1.insert(10);
s1.insert(40);
s1.insert(30);
s1.insert(50);
printSet(s1); //输出: 10 30 40 50 (已排序)
//指定排序规则为从大到小
set <int, MyCompare> s2; //仿函数指定排序规则, 声明一个s2,然后再插入数
s2.insert(10);
s2.insert(40);
s2.insert(30);
s2.insert(50);
for (set<int, Mycompare>::iterator it = s2.begin(); it != s2.end(); it++)
{
cout << *it << " ";
}
cout << endl; //输出: 50 40 30 10
}
示例二:set容器存放自定义数据类型 (必须指定排序规则)
class Person
{
public:
int m_Age;
string m_Name;
Person(string name, int age);
};
Person::Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
class comparePerson
{
public:
bool operator()(const Person& p1, const Person& p2) const
{
//按照年龄降序
return p1.m_Age > p2.m_Age;
}
};
void test08()
{
//自定义数据类型,必须指定排序规则
set <Person, comparePerson> s;
Person p1("刘备", 24);
Person p2("关羽", 23);
Person p3("张飞", 22);
Person p4("赵云", 25);
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
for (set<Person>::iterator it = s.begin(); it != s.end(); it++)
{
cout <<"姓名:" << (*it).m_Name << "年龄:" << it->m_Age << " " << endl;
// (*it).m_Name 与 it->m_Name等价。注意,不可写成*it.m_Name!
【注意】“.”表示属于,应用于类、结构体;而“->”应用于指针
}
}
8 map / multimap容器
8.1 map / multimap基本概念
简介:
- map中所有元素都是pair
- pair中第一个元素为key(键值),起到索引作用;第二个元素为value(实值)
- 所有元素都会根据元素的key自动排序
本质: map/ multimap属于关联式容器,底层结构是用二叉树实现
优点: 可以根据key,快速找到value (查找方便)
二者区别:
- map不允许容器中有重复key的元素
- multimap允许容器中有重复key的元素
8.2 map构造和赋值
函数原型:
构造:
map <T1, T2> mp;
map (const map &map);
赋值:
map& operator=(const map& mp);
8.3 map插入与删除
函数原型:
insert(elem);
clear();
erase(pos);
erase(begin, end);
erase(key);
void printMap(map<int, int>& m)
{
for (map<int, int>::iterator it=m.begin(); m!=m.end(); it++)
{
cout << "key = " << it->first << " value: " << (*it).second;
}
cout << endl;
}
void test01()
{
map <int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(2, 20));
m.insert(map<int, int>::value_type(3, 30));
m[4] = 40; //中括号不建议赋值,一般常用于访问
//因为如若访问时不小心使用到中括号,默认会自动生成一个value=0的键值对
printMap(m);
}
8.4 map大小和交换
函数原型:
size();
empty();
swap(st);
8.5 map查找与统计
函数原型
find(key);
//查找key是否存在,若存在,返回该键的元素迭代器;若不存在,返回set.end();count(key);
//统计key的元素个数,对于map而言只能出现0或1;multimap的返回值可以大于1
8.6 map排序
默认排序为从小到大。利用仿函数,可以改变排序规则
示例一:内置数据类型的排序
class Mycompare
{
public:
bool operator()(int v1, intv2)const
{
return v1>v2:
}
};
void test01()
{
map <int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(2, 20));
m.insert(map<int, int>::value_type(3, 30));
m.insert(pair<int, int>(4, 10));
m.insert(pair<int, int>(5, 20));
for (map<int, int, Mycompare>::iterator it = m.begin(); it!=m.end(); it++)
{
cout << "key = " << it->first << " value: " << (*it).second;
}
cout << endl;
}
示例二:自定义数据类型的排序,类似于set,详见7.8部分