C++之SLT中的容器
1. vector
vector(向量),是长度可以根据需要改变的数组。
1.1 定义
#include <iostream>
#include <vector>
using namespace std;
vector<typename> name;
//例:
vector<double> v1;
vector<int> v2;
vector<char> v3;
vector<int> vector1;
vector<int> vector2(10); // 指定10的空间大小
vector<int> vector3(10, 0); // 有了10个值了 每个值都是0
注意:如果 typename也是一个STL容器,定义的时候要记得在>>符号之间加上空格,因为有的编译器可能会把它视为移位操作,导致编译错误。如下面定义二维数组。
#include <iostream>
#include <vector>
using namespace std;
// vector数组:
vector<typename> arrayname[arraysize];
vector<int> v[100]; //一维长度已经固定为100
vector<vector<int> > name; //两维的长度都可变
1.2 vecor内元组的访问
- (1) 通过下标
vector[index]
#include <iostream>
#include <vector>
using namespace std;
vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);
cout << "item:" << vector4[vector4.begin()] << endl;
- (2) 通过迭代器
迭代器(iterator)可以理解为指针。vector::iterator it;
#include <iostream>
#include <vector>
using namespace std;
vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);
// 第一个
cout << " 修改前:vector4.front():" << vector4.front() << endl;
vector4.front() = 99; // 默认修改第一个
cout << " 修改后:vector4.front():" << vector4.front() << endl;
// 最后一个
cout << " 修改前:vector4.back():" << vector4.back() << endl;
vector4.back() = 777; // 默认修改最后
cout << " 修改后:vector4.back():" << vector4.back() << endl;
vector4.erase(vector4.begin()); // 移除第一个元素(内部:通过迭代器的位置 进行移除)
// 循环打印,默认 从大到小输出
for (int i = 0; i < vector4.size(); ++i) {
cout << "item:" << vector4[i] << endl;
}
1.3 常用函数
- (1) push_back()
push_back(x)就是在vector后加一个元素x。
#include <iostream>
#include <vector>
using namespace std;
vector<int> v;
v.push_back(10);//push_back(10)在v的末尾添加元素10
pop_back()用以删除vector的尾元素
- (2) pop_back()
用以删除vector的尾元素
#include <iostream>
#include <vector>
using namespace std;
vector<int> v;
v.insert(v.begin(), 40);
v.insert(v.begin(), 60);
v.pop_back();//用以删除vector的尾元素
- (3) size()
size()用来获得vector中元素个数。
#include <iostream>
#include <vector>
using namespace std;
vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);
// 循环打印,默认 从大到小输出
for (int i = 0; i < vector4.size(); ++i) {
cout << "item:" << vector4[i] << endl;
}
- (4) clear()
clear()用于清空vector中的所有元素。
#include <iostream>
#include <vector>
using namespace std;
vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);
vector4.clear();//清空vector中的所有元素
- (5) insert()
insert(it, x)用来向 vector的任意迭代器it处插入一个元素x。
#include <iostream>
#include <vector>
using namespace std;
vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);
- (6) erase()
erase()有两种用法: 1. 删除单个元素: erase(i) 即删除迭代器为it处的元素。 2. 删除一个区间内所有的元素: erase(first, last) 即删除[first, last)内的所有元素。
#include <iostream>
#include <vector>
using namespace std;
vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);
vector4.erase(vector4.begin()); // 移除第一个元素(内部:通过迭代器的位置 进行移除)
// 循环打印
for (int i = 0; i < vector4.size(); ++i) {
cout << "item:" << vector4[i] << endl;
}
vector4.erase(vector4.begin(),vector4.end()-1);
// 迭代器 循环遍历
for (auto iteratorVar = vector4.begin(); iteratorVar != vector4.end(); iteratorVar++) {
// 迭代器 当中指针操作 iteratorVar++
cout << "迭代器:" << *iteratorVar << endl;
}
1.4 常见用途
- (1) 存储数据
在一些元素不确定的场合可以使用。
- (2) 用邻接表存储图
2. set
set翻译为集合,内部:红黑树结构)是一个内部自动有序且不含重复元素的容器。 set name;
set数组:set arrayname[arraysize];
2.1 定义
#include <iostream>
#include <set>
using namespace std;
set<int, less<int>> setVar; // __x < __y 从小到大,默认情况下 就是 less
// 添加参数,不需要用迭代器,也不需要指定位置
setVar.insert(1);
setVar.insert(3);
setVar.insert(2);
setVar.insert(4);
// 重复插入,并不会报错 std::pair<iterator, bool>
pair<set<int, less<int>>::iterator, bool> res = setVar.insert(8);
// res.first 获取第一个元素 迭代器 当前迭代器 最后一个位置
// res.second 获取第二个元素 bool
bool insert_success = res.second;
if (insert_success) {
cout << "恭喜你,插入成功" << endl;
// 插入成功后,我用第一个元素遍历
for (; res.first != setVar.end(); res.first ++) {
cout << *res.first << endl;
}
} else {
cout << "哎,插入失败.." << endl;
}
// 全部遍历 auto 自动推到
for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
cout << *it << endl;
}
2.2 set内元素的访问
#include <iostream>
#include <set>
using namespace std;
set<int, less<int>> setVar; // __x < __y 从小到大,默认情况下 就是 less
// 添加参数,不需要用迭代器,也不需要指定位置
setVar.insert(1);
setVar.insert(3);
setVar.insert(2);
setVar.insert(4);
// 重复插入,并不会报错 std::pair<iterator, bool>
pair<set<int, less<int>>::iterator, bool> res = setVar.insert(8);
// res.first 获取第一个元素 迭代器 当前迭代器 最后一个位置
// res.second 获取第二个元素 bool
bool insert_success = res.second;
if (insert_success) {
cout << "恭喜你,插入成功" << endl;
// 插入成功后,我用第一个元素遍历
for (; res.first != setVar.end(); res.first ++) {
cout << *res.first << endl;
}
} else {
cout << "哎,插入失败.." << endl;
}
// 全部遍历 auto 自动推到
for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
cout << *it << endl;
}
2.3 常用函数
- (1) insert()
insert(x) 将x插入set容器中,并自动递增排序和去重。
- (2) find()
find(value)返回set中对应值为value的迭代器,如果没找到则返回系统默认值。
#include <iostream>
#include <set>
using namespace std;
set<int> setVar;
// 添加参数,不需要用迭代器,也不需要指定位置
setVar.insert(1);
setVar.insert(3);
setVar.insert(2);
setVar.insert(4);
const set<int>::iterator it = setVar.find(1);
cout << *it << endl;
- (3) size()
size()用来获得set中元素个数。
- (4) clear()
clear()用于清空set中的所有元素。
- (5) erase()
erase()有两种用法: 1. 删除单个元素: erase(it),it为所需要删除元素的迭代器,可结合find()函数使用。 erase(value),value为所需要删除的元素。 2. 删除一个区间内所有的元素: erase(first, last) 即删除[first, last)内的所有元素。
#include <iostream>
#include <set>
using namespace std;
set<int> setVar;
// 添加参数,不需要用迭代器,也不需要指定位置
setVar.insert(1);
setVar.insert(3);
setVar.insert(2);
setVar.insert(4);
setVar.erase(2);
setVar.erase(setVar.find(2),setVar.end());
// 全部遍历 auto 自动推到
for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
cout << *it << endl;
}
2.4 set 谓词 设计对象的排序
// 谓词 设计对象的排序
#include <iostream>
#include <set>
using namespace std;
class Person {
public:
string name;
int id;
Person(string name, int id) : name(name), id(id) {}
};
// 真正的谓词
struct doCompareAction {
public:
bool operator() (const Person& __x, const Person& __y) {
return __x.id > __y.id;//id 大的排前面
}
};
int main() {
// 默认是 less return 对象1 < 对象2;
set<Person, doCompareAction> setVar;
// 构建对象
Person p1 ("小明", 1);
Person p2 ("小美", 2);
Person p3 ("小梅", 3);
// 把构建的对象 插入到 set 容器里面去
setVar.insert(p1);
setVar.insert(p2);
setVar.insert(p3);
for (set<Person>::iterator it = setVar.begin(); it != setVar.end() ; it ++) {
cout << it->name << " , " << it->id << endl;
}
return 0;
}
2.5 常见用途
遇到需要去重但不方便直接开数组的情况,可尝试用set解决。
3. string
#include <iostream>
#include <string>
using namespace std;
3.1 定义
string str;
string str = "abcd";
3.2 string中内容的访问
- (1) 通过下标
str[index] 如果要读入和输出整个字符串,则只能用cin和cout。
- (2) 通过迭代器
string不想其他STL容器那样需要参数,因此可以直接如下定义:
string::iterator it;
string和vector一样,支持直接对迭代器进行加减,如str.begin() + 3。
3.3 常用函数
- (1) +=
string的加法,可以将两个string直接拼接起来。
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "abc", str2 = "xyz", str3;
str3 = str1 + str2;
str1 += str2;
cout << str1 << endl;
cout << str3 << endl;
return 0;
}
- (2) 比较
两个string类型可直接用==、!=、< 、<=、>、>=比较大小,比较规则是字典序(即"aac"小于"aba")。
- (3) length()/size()
size()和length()基本相同
- (4) insert()
1.insert(pos, string),在pos号位置插入string(从0开始)。
#include <iostream>
#include <string>
using namespace std;
int main(){
string str1 = "abcxyz", str2 = "opq";
str1.insert(3, str2);
cout << str1 << endl;
return 0;
}
insert(it, it2, it3),it为原字符串的欲插入位置,it2和it3为待插字符串的首尾迭代器,表示[it2, it3)将被插在it的位置上。
#include <iostream>
#include <string>
using namespace std;
int main(){
string str1 = " Hi, girl!", str2 = "See you.";
str1.insert(str1.begin(), str2.begin(), str2.end());
cout << str1 << endl;
return 0;
}
- (5) erase()
删除单个元素:erase(i)即删除迭代器为it处的元素。
删除一个区间内所有的元素:
1.str.erase(first, last),其中first为区间的起始迭代器,
而last为需要删除的区间的末尾迭代器的下一个地址。
2.str.erase(pos, length),其中pos为需要开始删除的起始位置,
而length为删除的字符个数。
- (6) clear()
clear()用于清空string中的所有元素。
- (7) substr()
(8) substr(pos, len)返回从pos号开始、长度为len的子串。
string::npos string::npos是一个常数,其本身的值为-1,是unsighed_int类型。
string::npos用以作为find()函数失配时的返回值。
- (9) find()
str.find(str2),
当str2是str的子串时,返回其在str中第一次出现的位置;
如果str2不是str的子串,则返回系统默认值
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "abc";
stribf str2="b";
unsigned long i = str.find(str2);
cout << str[i] << endl;
return 0;
}
str.find(str2, pos),从str的pos号开始匹配str2,返回值与上相同。
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Thank you for your help.";
string str1 = "you";
string str2 = "me";
if(str.find(str1) != string::npos){
cout << str.find(str1) << endl;
}
if(str.find(str1, 7) != string::npos){
cout << str.find(str1, 7)<< endl;
}
if(str.find(str2) != string::npos){
cout << str.find(str2) << endl;
}else{
cout << "There is no position for me." << endl;
}
return 0;
}
- (9) replace()
str.replace(pos, len, str2)把str从pos位开始、长度为len的字符串换成str2.
str.replace(it1, it2, str2)把str的迭代器[it1, it2)范围的子串换成str2.
#include <iostream>
#include <string>
using namespace std;
int main(){
string str = "Thank you for your help.";
string str1 = "HAPPY";
string str2 = "BITE";
cout << str.replace(10, 2, str1) << endl;
cout << str.replace(str.begin(), str.begin() + 1, str2) << endl;
return 0;
}
4. map
map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器)。
4.1 定义
map<typename1, typename2> mp;
如果是字符串到整型的映射,必须使用string而不能用char数组:
map<string, int> mp;
map的键和值也可以是STL容器:
map<set<int>, string> mp;
4.2 map内内容的访问
- (1) 通过下标
map中的键是唯一的。mp['key']
- (2) 通过迭代器
map<typename1, typename2>::iterator it;
#include <iostream>
#include <map>
using namespace std;
int main() {
map<char, int> mp;
mp['a'] = 1;
mp['b'] = 2;
mp['c'] = 3;
map<char, int>::iterator it = mp.find('b');
cout <<"key:" << it->first<<" value:" <<it->second << endl;
return 0;
}
4.3 常用函数
- (1) find()
#include <iostream>
#include <map>
using namespace std;
int main() {
map<char, int> mp;
mp['a'] = 1;
mp['b'] = 2;
mp['c'] = 3;
map<char, int>::iterator it = mp.find('b');
cout <<"key:" << it->first<<" value:" <<it->second << endl;
return 0;
}
- (2) erase()
1.删除单个元素:
1.mp.erase(it),it为欲删除的元素的迭代器
2.mp.erase(key),key为欲删除的映射的键。
#include <iostream>
#include <map>
using namespace std;
int main() {
map<char, int> mp;
mp['a'] = 1;
mp['b'] = 2;
mp['c'] = 3;
mp['d'] = 4;
map<char, int>::iterator it = mp.find('b');
mp.erase(it); // 利用迭代器删除b 2
mp.erase('c'); // 删除键为c的映射,即c 3
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++) {
cout <<"key:" << it->first<<" value:" <<it->second << endl;
}
return 0;
}
删除一个区间内所有的元素:
mp.erase(first, last),删除[first, last)内的所有元素,first为起始迭代器,last为末尾迭代器的下一个地址。
#include <iostream>
#include <map>
using namespace std;
int main() {
map<char, int> mp;
mp['a'] = 1;
mp['b'] = 2;
mp['c'] = 3;
map<char, int>::iterator it = mp.find('b');
mp.erase(it, mp.end());
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++) {
cout <<"key:" << it->first<<" value:" <<it->second << endl;
}
return 0;
}
- (3) size()
- (4) clear()
4.4 常见用处
1. 需要建立字符(或字符串)与整数之间映射的题目;
2. 判断大整数或其他类型数据是否存在的题目,可以把map当bool数组用;
3. 字符串和字符串的映射。
5. multimap
所谓“相似”,指的是 multimap 容器具有和 map 相同的特性,即 multimap 容器也用于存储 pair<const K, T> 类型的键值对(其中 K 表示键的类型,T 表示值的类型),其中各个键值对的键的值不能做修改;并且,该容器也会自行根据键的大小对存储的所有键值对做排序操作。和 map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。
5.1 定义
通过调用 multimap 类模板的默认构造函数,可以创建一个空的 multimap 容器:
#include <iostream>
#include <map>
using namespace std;
//multimap 容器类模板的定义如下:
template < class Key, // 指定键(key)的类型
class T, // 指定值(value)的类型
class Compare = less<Key>, // 指定排序规则
class Alloc = allocator<pair<const Key,T> > // 指定分配器对象的类型
> class multimap;
可以看到,multimap 容器模板有 4 个参数,其中后 2 个参数都设有默认值。
大多数场景中,我们只需要设定前 2 个参数的值,有些场景可能会用到第 3 个参数,
但最后一个参数几乎不会用到。
// 注意:map会对key进行排序,默认 key不能重复
map<int, string> mapVar;
// 添加数据
// 第一种方式
mapVar.insert(pair<int, string>(1, "一"));
// 第二种方式
mapVar.insert(make_pair(2, "二"));
// 第三种方式
mapVar.insert(map<int, string>::value_type (3, "三"));
// 上面三种方式 key不能重复
// 思考:既然会对key进行排序,那么key是不能重复的(会插入失败)
mapVar.insert(pair<int, string>(3, "三3"));
// 第四种方式 mapVar[key]=Value
mapVar[4] = "四";
mapVar[4] = "肆"; // 第四种方式覆盖/替换(常用)
在创建 multimap 容器的同时,还可以进行初始化操作:
#include <iostream>
#include <map>
using namespace std;
int main() {
//创建并初始化 multimap 容器
multimap<int, string> mapVar{ {1, "http://c.biancheng.net/c/"},
{2, "http://c.biancheng.net/python/"},
{3, "http://c.biancheng.net/stl/"} };
/**
* typedef typename _Rep_type::iterator iterator; 之前常规的迭代器
typedef typename _Rep_type::const_iterator const_iterator; 只读的,只能读,不能修改 的迭代器
typedef typename _Rep_type::reverse_iterator reverse_iterator; 倒序打印的迭代器
*/
// 循环打印,迭代器
for (map<int, string>::iterator it = mapVar.begin() ; it != mapVar.end() ; it ++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
cout << endl;
return 0;
}
实际上,我们完全可以先手动创建好键值对,然后再用其初始化 multimap 容器。下面程序使用了 2 种方式创建 pair 类型键值对,再用其初始化 multimap 容器,它们是完全等价的:
//创建并初始化 multimap 容器
multimap<int, string> mapVar{ pair<int,string>{1, "Java"},
pair<int,string>{2, "C++"},
pair<int,string>{3, "Dart"} };
multimap<int, string> mapVar{make_pair(1, "Java"),
make_pair(2, "C++"),
make_pair(3, "Dart")};
除此之外,通过调用 multimap 类模板的拷贝(复制)构造函数,也可以初始化新的 multimap 容器。例如:
//创建并初始化 multimap 容器
multimap<int, string> mapVar{ pair<int,string>{1, "Java"},
pair<int,string>{2, "C++"},
pair<int,string>{3, "Dart"} };
multimap<int, string> newMapVar(mapVar);
multimap 类增添了移动构造函数。即当有临时的 multimap 容器作为参数初始化新 multimap 容器时,其底层就会调用移动构造函数来实现初始化操作。举个例子:
#include <iostream>
#include <map>
using namespace std;
//创建一个会返回临时 multimap 对象的函数
multimap<int, string> disMultiMap() {
multimap<int, string> tempMultiMap{
{4, "D"},
{5, "F"} };
return tempMultiMap;
}
int main() {
//调用 multimap 类模板的移动构造函数创建 newMapVar 容器
multimap<int, string> newMapVar(disMultiMap());
/**
* typedef typename _Rep_type::iterator iterator; 之前常规的迭代器
typedef typename _Rep_type::const_iterator const_iterator; 只读的,只能读,不能修改 的迭代器
typedef typename _Rep_type::reverse_iterator reverse_iterator; 倒序打印的迭代器
*/
// 循环打印,迭代器
for (map<int, string>::iterator it = mapVar.begin(); it != mapVar.end(); it++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
cout << endl;
return 0;
}
multimap 类模板还支持从已有 multimap 容器中,选定某块区域内的所有键值对,用作初始化新 multimap 容器时使用。例如:
#include <iostream>
#include <map>
using namespace std;
int main() {
multimap<int, string> mapVar{
{3, "C"},
{4, "D"},
{5, "F"}};
multimap<int, string> newMapVar(mapVar.begin(), mapVar.end());
// 循环打印,迭代器
for (map<int, string>::iterator it = mapVar.begin(); it != mapVar.end(); it++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
}
multimap 类模板共可以接收 4 个参数,其中第 3 个参数可用来修改 multimap 容器内部的排序规则。默认情况下,此参数的值为std::less,这意味着以下 2 种创建 multimap 容器的方式是等价的:
#include <iostream>
#include <map>
using namespace std;
int main() {
multimap<int, string> mapVar{
{3, "C"},{4, "D"},{5, "F"}};
// 循环打印,迭代器
for (map<int, string>::iterator it = mapVar.begin(); it != mapVar.end(); it++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
cout << endl;
multimap<int, string, less<int>> newMapVar{
{3, "C"},{4, "D"},{5, "F"}};
// 循环打印,迭代器
for (map<int, string>::iterator it = newMapVar.begin(); it != newMapVar.end(); it++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
cout << endl;
multimap<int, string, greater<int>> greaterMapVar{
{3, "C"},{4, "D"},{5, "F"}};
// 循环打印,迭代器
for (map<int, string>::iterator it = greaterMapVar.begin(); it != greaterMapVar.end(); it++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
cout << endl;
return 0;
}
5.2 成员方法
表 1 中部分成员方法的用法
#include <iostream>
#include <map> //map
using namespace std;
int main(){
//创建并初始化 multimap 容器
multimap<char, int>mymultimap{ {'a',10},{'b',20},{'b',15}, {'c',30} };
//输出 mymultimap 容器存储键值对的数量
cout << mymultimap.size() << endl;
//输出 mymultimap 容器中存储键为 'b' 的键值对的数量
cout << mymultimap.count('b') << endl;
for (auto iter = mymultimap.begin(); iter != mymultimap.end(); ++iter) {
cout << iter->first << " " << iter->second << endl;
}
return 0;
}
#include <iostream>
#include <map>
using namespace std;
int main() {
// 1.key可以重复, 2.key重复的数据可以分组, 3.key会排序, 4.value不会排序
multimap<int, string> multimapVar;
multimapVar.insert(make_pair(10, "十个1"));
multimapVar.insert(make_pair(10, "十个2"));
multimapVar.insert(make_pair(10, "十个3"));
multimapVar.insert(make_pair(30, "三十1"));
multimapVar.insert(make_pair(30, "三十3"));
multimapVar.insert(make_pair(30, "三十2"));
multimapVar.insert(make_pair(20, "二十1"));
multimapVar.insert(make_pair(20, "二十2"));
multimapVar.insert(make_pair(20, "二十3"));
for (auto iteratorVar = multimapVar.begin(); iteratorVar != multimapVar.end() ; iteratorVar ++) {
cout << iteratorVar->first << "," << iteratorVar->second << endl;
}
cout << endl;
//核心功能是分组
int result;
cout << "请输入你要查询的key,为int类型:" << endl;
cin >> result;
multimap<int, string>::iterator iteratorVar = multimapVar.find(result);
while (iteratorVar != multimapVar.end()) {
cout << iteratorVar->first << "," << iteratorVar->second << endl;
// 需要自己做逻辑控制,不然有问题
iteratorVar++;
if (iteratorVar->first != result) {
break;; // 循环结束
}
// 严谨性
if (iteratorVar == multimapVar.end()) {
break;; // 循环结束
}
}
return 0;
}
6. queue
queue(队列)是STL中实现的一个先进先出的容器。
6.1 定义
queue<typename> name;
6.2 queue内内容的访问
因为队列是一种先进先出的数据结构,因此在SLT中只能用front()访问队首元素,通过back()访问队尾元素。
6.3 常用函数
- (1) push()
push(x)将x压入队列
- (2) front()、back()
front()用于访问队首元素,back()用于访问队尾元素。
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q;
for (int i = 1; i <= 5; i++) {
q.push(i); //push(i)用以将i压入队列
}
cout << "first:" << q.front()<< " last:" << q.back() << endl;
return 0;
}
- (3) pop()
pop()令队首元素出队
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q;
for (int i = 1; i <= 5; i++) {
q.push(i); //push(i)用以将i压入队列
}
for(int i = 1; i <= 3; i++) {
q.pop(); //出队首元素3次(依次为1 2 3)
}
cout << "first:" << q.front()<< " last:" << q.back() << endl;
return 0;
}
- (4) empty()
empty()检测 queue是否为空,返回true则空,返回false则非空。
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q;
if(q.empty()){
cout << "Empty" << endl;
}else{
cout << "Not Empty" << endl;
}
q.push(1);
if(q.empty()){
cout << "Empty" << endl;
}else{
cout << "Not Empty" << endl;
}
return 0;
}
- (5) size()
6.4 常见用处
当需要实现广度优先搜索时,可以不用自己手动实现一个队列,而是用queue作为代替,以提高程序的准确性。
**注意:**使用front()和pop()函数前,必须用empty()判断队列是否为空。
7. priority_queue
priority_queue又叫优先队列,其底层是用堆进行实现的。队首元素一定是当前队列中优先级最高的那一个。
可以在任何时间往优先队列里加入(push)元素,优先队列底层的堆(heap)会随时调整结构,使得每次的队首元素都是优先最大的。
关于这里的优先级则是规定出来的。
7.1 定义
#include <iostream>
#include <queue>
using namespace std;
priority_queue<typename> name;
7.2 priority_queue内内容的访问
和queue不同,priority_queue没有front()和back()函数,
只能通过top()函数来访问队首元素(堆顶元素),也就是优先级最高的元素。
#include <iostream>
#include <queue>
using namespace std;
int main() {
priority_queue<int> q;
q.push(1);
q.push(4);
q.push(5);
cout << q.top() << endl;
return 0;
}
7.3 常用函数
- (1) push()
- (2) top()
获得队首元素(即堆顶元素)出队。
- (3) pop()
#include <iostream>
#include <queue>
using namespace std;
int main() {
priority_queue<int> q;
q.push(1);
q.push(4);
q.push(5);
cout << q.top() << endl;
q.pop();
cout << q.top() << endl;
return 0;
}
- (4) empty()
- (5) size()
7.4 priority_queue内元素优先级的设置
- (1) 基本数据类型
此处指的基本数据类型就是int型、 double型、char型等可以直接使用的数据类型,
优先队列对他们的优先级设置一般是数字大的优先级越高。
下面两种定义方式是等价的(注意最后两个>之间有一个空格):
priority_queue<int> q;
priority_queue<int, vector<int>, less<int> > q;
第二种定义方法尖括号内多了两个参数:
vector<int>填写的是来承载底层数据结构堆(heap)的容器。
如果第一个参数是double型或char型,则此处只需填写vector<double>或vector<char>;
less<int>是对第一个参数的比较类。less<int>表示数字大的优先级越大,
而greater<int>表示数字小的优先级越大。
#include <stdio.h>
#include <queue>
using namespace std;
int main(void){
priority_queue<int, vector<int>, greater<int> > q; //让优先队列总是把最小的元素放队首
q.push(3);
q.push(4);
q.push(1);
printf("%d\n", q.top());
return 0;
}
- (2) 结构体
通过改变小于号"<"的功能,即把它重载(overload)为大于号的功能。
现在希望按水果的价格高的为优先级高,需要重载小于号:
struct fruit {
string name;
int price;
// friend为友元,bool operator < (fruit f1, fruit f2)对fruit类型的操作符"<"进行重载
friend bool operator < (fruit f1, fruit f2) {
return f1.price < f2.price; // 重载后小于号还是小于号的作用。
}
};
#include <iostream>
#include <string>
#include <queue>
using namespace std;
struct fruit {
string name;
int price;
friend bool operator < (fruit f1, fruit f2) {
return f1.price < f2.price; //水果的价格高的为优先级高
}
}f1, f2, f3;
int main(void){
priority_queue<fruit> q;
f1.name = "桃子";
f1.price = 3;
f2.name = "苹果";
f2.price = 4;
f3.name = "香蕉";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
同理,希如果望按水果的价格低的为优先级高,只需要把return中的小于号改为大于号。
#include <iostream>
#include <string>
#include <queue>
using namespace std;
struct fruit {
string name;
int price;
friend bool operator < (fruit f1, fruit f2) {
return f1.price > f2.price; //水果的价格低的为优先级高
}
}f1, f2, f3;
int main(void){
priority_queue<fruit> q;
f1.name = "桃子";
f1.price = 3;
f2.name = "苹果";
f2.price = 4;
f3.name = "香蕉";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
记住:**优先队列的这个函数与sort中的函数效果是相反的!**
在排序中,return f1.price > f2.price;表示按价格从低到高,
而在优先队列中却是把价格低的放队首。
这是因为优先队列本身默认的规则就是优先级高的放队首,
因此把小于号重载为>的功能时只是把这个规则反了一下。
可以把sort中的cmp函数卸载结构体外面:
#include <iostream>
#include <string>
#include <queue>
using namespace std;
struct fruit {
string name;
int price;
}f1, f2, f3;
struct cmp {
bool operator () (fruit f1, fruit f2) {
return f1.price > f2.price; //优先最小的,水果的价格低的为优先级高
}
};
int main(){
priority_queue<fruit, vector<fruit>, cmp> q; //这种情况只能这样定义优先队列
f1.name = "桃子";
f1.price = 3;
f2.name = "苹果";
f2.price = 4;
f3.name = "香蕉";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
如果结构体内的数据庞大(例如出现字符串或数组) 建议使用引用来提升效率,此时比较类的参数中要加入const和&, 如下所示:
friend bool operator () (const fruit &f1, const fruit &f2) {
return f1.price > f2.price;
}
bool operator () (const fruit &f1, const fruit &f2) {
return f1.price > f2.price;
}
#include <iostream>
#include <set>
using namespace std;
class fruit {
public:
string name;
int price;
fruit(string name,int price):name(name),price(price){}
};
struct doCompareFruit{
public:
bool operator () (const fruit &f1, const fruit &f2) {
return f1.price < f2.price;//价格低优先级高
}
};
int main() {
// 默认是 less return 对象1 < 对象2;
set<fruit, doCompareFruit> setVar;
// 构建对象
fruit f1 ("苹果", 10);
fruit f2 ("香蕉", 20);
fruit f3 ("榴莲", 30);
// 把构建的对象 插入到 set 容器里面去
setVar.insert(f1);
setVar.insert(f2);
setVar.insert(f3);
for (set<fruit>::iterator it = setVar.begin(); it != setVar.end() ; it ++) {
cout << it->name << " , " << it->price << endl;
}
return 0;
}
7.5 常见用处
priority_queue可以解决一些贪心问题,也可以对DijKstra算法进行优化(因为优先队列的本质是堆)。
注意:使用top()函数前,要用empty()判断优先队列是否为空。
8. stack
栈,是STL实现的一个后进后出的容器。
8.1 定义
#include <iostream>
#include <stack>
using namespace std;
stack<typename> name;
8.2 stack内内容的访问
栈本身就是一种后进先出、先进后出的数据结构,在STL中的stack中只能通过top()来访问栈顶元素
#include <iostream>
#include <stack>
using namespace std;
int main(){
stack<int> st;
for(int i = 1; i <= 5; i++) {
st.push(i);
}
cout << st.top() << endl;
return 0;
}
8.3 常用函数
- (1) push()
- (2) top()
- (3) pop()
弹出栈顶元素。
#include <iostream>
#include <stack>
using namespace std;
int main(){
stack<int> st;
for(int i = 1; i <= 5; i++) {
st.push(i);
}
st.pop();
cout << st.top() << endl;
return 0;
}
- (4) empty()
- (5) size()
8.4 常见用处
stack用来模拟一些递归,防止程序对栈内存的限制而导致程序出错
9. pair
pair可以看作内部有两个元素的结构体,且这两个元素的类型是可以指定的,如:
struct pair {
typename1 first;
typename2 second;
};
9.1 定义
有两个参数,分别对应first和second的数据类型,他们可以是任意基本数据类型或容器。
pair<typename1, typename2> name;
如:
pair<string, int> p;
如果想在定义时初始化:
pair<string, int> p("haha", 5);
如果想在代码中临时构建一个pair,有如下两种方法:
pair<string, int>("haha", 5);
make_pair("haha", 5);
9.2 pair内内容的访问
pair中只有两个元素,分别是first和second,只需按正常结构体的方式访问即可
#include <iostream>
#include <utility>
using namespace std;
int main(){
pair<string, int> p;
p.first = "haha";
p.second = 5;
cout << p.first << " " << p.second << endl;
p = make_pair("xixi", 3); //自带函数
cout << p.first << " " << p.second << endl;
p = pair<string, int>("wuwu", 555);
cout << p.first << " " << p.second << endl;
return 0;
}
9.3 常用函数
- 比较操作数
两个pair类型数据可直接用==、!=、<等比较大小,规则是先比first,first相等时再比second。
#include <iostream>
#include <utility>
#include <string>
using namespace std;
int main(void){
pair<int, int> p1(5, 55);
pair<int, int> p2(5, 555);
pair<int, int> p3(10, 5);
if(p1 < p3) cout << "p1 < p3" << endl;
if(p1 <= p3) cout << "p1 <= p3" << endl;
if(p1 < p2) cout << "p1 < p2" << endl;
return 0;
}
9.4 常见用处
1. 用来代替二元结构体及其构造函数,可以节省编码时间。
2. 作为map的键值对来进行插入。
#include <iostream>
#include <map>
using namespace std;
int main(){
map<string, int> mp;
mp.insert(make_pair("heihei", 5));
mp.insert(pair<string, int>("haha", 2));
for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) {
cout << it->first << " " << it -> second << endl;
}
return 0;
}
10. list
List是stl实现的双向链表,与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢
10.1 定义
#include <iostream>
#include <list>
using namespace std;
list<int> list1; //创建空list
list<int> list2(5); //创建含有5个元素的list
list<int> list3(3,2); //创建含有3个元素的list
list<int> list4(lst2); //使用lst2初始化lst4
list<int> list5(list2.begin(),list2.end()); //同lst4
10.2 List常用操作函数
list<int> listVar;
listVar.assign() //给list赋值
listVar.back() //返回最后一个元素
listVar.begin() //返回指向第一个元素的迭代器
listVar.clear() //删除所有元素
listVar.empty() //如果list是空的则返回true
listVar.end() //返回末尾的迭代器
listVar.erase() // 删除一个元素
listVar.front() //返回第一个元素
listVar.get_allocator() //返回list的配置器
listVar.insert() //插入一个元素到list中
listVar.max_size() //返回list能容纳的最大元素数量
listVar.merge() //合并两个list
listVar.pop_back() //删除最后一个元素
listVar.pop_front()// 删除第一个元素
listVar.push_back() //在list的末尾添加一个元素
listVar.push_front()// 在list的头部添加一个元素
listVar.rbegin() //返回指向第一个元素的逆向迭代器
listVar.remove() //从list删除元素
listVar.remove_if() //按指定条件删除元素
listVar.rend() //指向list末尾的逆向迭代器
listVar.resize() //改变list的大小
listVar.reverse()// 把list的元素倒转
listVar.size() //返回list中的元素个数
listVar.sort() //给list排序
listVar.splice() //合并两个list
listVar.swap() //交换两个list
listVar.unique()// 删除list中重复的元素
10.3 List使用示例:
#include <iostream>
#include <list>
using namespace std;
int main() {
list<int> listVar;
// 插入操作
listVar.push_front(50); // 插入到前面 明确
listVar.push_back(60); // 插入到后面
listVar.insert(listVar.begin(), 70); // 插入到前面 灵活
listVar.insert(listVar.end(), 80); // 插入到后面
// 修改操作
listVar.back() = 88;
listVar.front() = 55;
// 删除
listVar.erase(listVar.begin()); // 删除最前面的 55
listVar.erase(listVar.end()); // 删除最后面的 88
// list 迭代器
// 不用通过角标去访问,也不能修改 遍历
for (list<int>::iterator it = listVar.begin(); it != listVar.end() ; it ++) {
cout << *it << endl;
}
return 0;
}
// list的学习。 Java:ArrayList采用Object[]数组, C++的list 内部:采用链表
#include <iostream>
#include <list>
#include <numeric>
#include <algorithm>
using namespace std;
typedef list<int> LISTINT;
typedef list<int> LISTCHAR;
int main() {
//用LISTINT创建一个list对象
LISTINT listOne;
//声明i为迭代器
LISTINT::iterator i;
listOne.push_front(3);
listOne.push_front(2);
listOne.push_front(1);
listOne.push_back(4);
listOne.push_back(5);
listOne.push_back(6);
cout << "listOne.begin()--- listOne.end():" << endl;
for (i = listOne.begin(); i != listOne.end(); ++i)
cout << *i << " ";
cout << endl;
LISTINT::reverse_iterator ir;
cout << "listOne.rbegin()---listOne.rend():" << endl;
for (ir = listOne.rbegin(); ir != listOne.rend(); ir++) {
cout << *ir << " ";
}
cout << endl;
int result = accumulate(listOne.begin(), listOne.end(), 0);
cout << "Sum=" << result << endl;
cout << "------------------" << endl;
//用LISTCHAR创建一个list对象
LISTCHAR listTwo;
//声明i为迭代器
LISTCHAR::iterator j;
listTwo.push_front('C');
listTwo.push_front('B');
listTwo.push_front('A');
listTwo.push_back('D');
listTwo.push_back('E');
listTwo.push_back('F');
cout << "listTwo.begin()---listTwo.end():" << endl;
for (j = listTwo.begin(); j != listTwo.end(); ++j)
cout << char(*j) << " ";
cout << endl;
j = max_element(listTwo.begin(), listTwo.end());
cout << "The maximum element in listTwo is: " << char(*j) << endl;
return 0;
}
#include <iostream>
#include <list>
using namespace std;
typedef list<int> INTLIST;
//从前向后显示list队列的全部元素
void put_list(INTLIST list, char *name) {
INTLIST::iterator plist;
cout << "The contents of " << name << " : ";
for (plist = list.begin(); plist != list.end(); plist++)
cout << *plist << " ";
cout << endl;
}
//测试list容器的功能
int main() {
//list1对象初始为空
INTLIST list1;
INTLIST list2(5, 1);
INTLIST list3(list2.begin(), --list2.end());
//声明一个名为i的双向迭代器
INTLIST::iterator i;
put_list(list1, "list1");
put_list(list2, "list2");
put_list(list3, "list3");
list1.push_back(7);
list1.push_back(8);
cout << "list1.push_back(7) and list1.push_back(8):" << endl;
put_list(list1, "list1");
list1.push_front(6);
list1.push_front(5);
cout << "list1.push_front(6) and list1.push_front(5):" << endl;
put_list(list1, "list1");
list1.insert(++list1.begin(), 3, 9);
cout << "list1.insert(list1.begin()+1,3,9):" << endl;
put_list(list1, "list1");
//测试引用类函数
cout << "list1.front()=" << list1.front() << endl;
cout << "list1.back()=" << list1.back() << endl;
list1.pop_front();
list1.pop_back();
cout << "list1.pop_front() and list1.pop_back():" << endl;
put_list(list1, "list1");
list1.erase(++list1.begin());
cout << "list1.erase(++list1.begin()):" << endl;
put_list(list1, "list1");
list2.assign(8, 1);
cout << "list2.assign(8,1):" << endl;
put_list(list2, "list2");
cout << "list1.max_size(): " << list1.max_size() << endl;
cout << "list1.size(): " << list1.size() << endl;
cout << "list1.empty(): " << list1.empty() << endl;
put_list(list1, "list1");
put_list(list3, "list3");
cout << "list1>list3: " << (list1 > list3) << endl;
cout << "list1<list3: " << (list1 < list3) << endl;
list1.sort();
put_list(list1, "list1");
list1.splice(++list1.begin(), list3);
put_list(list1, "list1");
put_list(list3, "list3");
return 0;
}