文章目录
参考:https://zhuanlan.zhihu.com/p/127860466
参考:https://blog.csdn.net/google19890102/article/details/51720305
参考:http://c.biancheng.net/view/338.html C++迭代器(STL迭代器)iterator详解
参考:https://blog.csdn.net/hnjzsyjyj/article/details/108929993 用pair做优先队列priority_queue元素的例子
map
map简介
map是STL(中文标准模板库)的一个关联容器。
- 可以将任何基本类型映射到任何基本类型。如int array[100]事实上就是定义了一个int型到int型的映射。
- map提供一对一的数据处理,key-value键值对,其类型可以自己定义,第一个称为关键字,第二个为关键字的值
- map内部是自动排序的
map的用法
- 引入包
#include<map>
-
map对象的定义和初始化
map是键-值对的组合,有以下的一些定义的方法: -
map<k, v> m;
-
map<k, v> m(m2);
-
map<k, v> m(b, e);
上述第一种方法定义了一个名为m的空的map对象;第二种方法创建了m2的副本m;第三种方法创建了map对象m,并且存储迭代器b和e范围内的所有元素的副本。
map的value_type是存储元素的键以及值的pair类型,键为const。
map容器内元素的访问
- 通过下标进行访问
如:maps[‘c’]=5; - 通过迭代器进行访问
map可以使用it->first来访问键,使用it->second访问值
#include<map>
#include<iostream>
using namespace std;
int main()
{
map<char,int>maps;
maps['d']=10;
maps['e']=20;
maps['a']=30;
maps['b']=40;
maps['c']=50;
maps['r']=60;
for(map<char,int>::iterator it=mp.begin();it!=mp.end();it++)
{
cout<<it->first<<" "<<it->second<<endl;
}
return 0;
}
map的常用用法
-
map中元素的插入
在map中元素有两种插入方法:- 使用下标
- 使用insert函数
在map中使用下标访问不存在的元素将导致在map容器中添加一个新的元素。
insert函数的插入方法主要有如下:
- m.insert(e)
- m.insert(beg, end)
- m.insert(iter, e)
上述的e一个value_type类型的值。beg和end标记的是迭代器的开始和结束。
两种插入方法如下面的例子所示:
#include <stdio.h> #include <map> using namespace std; int main(){ map<int, int> mp; for (int i = 0; i < 10; i ++){ mp[i] = i; } for (int i = 10; i < 20; i++){ mp.insert(make_pair(i, i)); } map<int, int>::iterator it; for (it = mp.begin(); it != mp.end(); it++){ printf("%d-->%d\n", it->first, it->second); } return 0; }
-
maps.find() 查找一个元素
注意:上述采用下标的方法读取map中元素时,若map中不存在该元素,则会在map中插入。
因此,若只是查找该元素是否存在,可以使用函数count(k),该函数返回的是k出现的次数;若是想取得key对应的值,可以使用函数
find(k)`,该函数返回的是指向该元素的迭代器。
map<string,int>::iterator it;
it=maps.find("123");
- maps.clear()清空
- maps.erase()删除一个元素
//迭代器刪除
it = maps.find("123");
maps.erase(it);
//关键字删除
int n = maps.erase("123"); //如果刪除了返回1,否则返回0
//用迭代器范围刪除 : 把整个map清空
maps.erase(maps.begin(), maps.end());
//等同于mapStudent.clear()
- maps.szie()长度
- maps.begin()返回指向map头部的迭代器
- maps.end()返回指向map末尾的迭代器
- maps.rbegin()返回指向map尾部的逆向迭代器
- maps.rend()返回指向map头部的逆向迭代器
- maps.empty()判断其是否为空
- maps.swap()交换两个map
迭代器iterator
要访问顺序容器和关联容器中的元素,需要通过“迭代器(iterator)”进行。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。
四种迭代器
- 正向迭代器,定义方法如下:
容器类名::iterator 迭代器名;
- 常量正向迭代器,定义方法如下:
容器类名::const_iterator 迭代器名;
- 反向迭代器,定义方法如下:
容器类名::reverse_iterator 迭代器名;
- 常量反向迭代器,定义方法如下:
容器类名::const_reverse_iterator 迭代器名;
迭代器用法示例
通过迭代器可以读取它指向的元素,*迭代器名
就表示迭代器指向的元素。通过非常量迭代器还能修改其指向的元素。
迭代器都可以进行++
操作。反向迭代器和正向迭代器的区别在于:
- 对正向迭代器进行
++
操作时,迭代器会指向容器中的后一个元素; - 而对反向迭代器进行
++
操作时,迭代器会指向容器中的前一个元素。
下面的程序演示了如何通过迭代器遍历一个 vector 容器中的所有元素。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v; //v是存放int类型变量的可变长数组,开始时没有元素
for (int n = 0; n<5; ++n)
v.push_back(n); //push_back成员函数在vector容器尾部添加一个元素
vector<int>::iterator i; //定义正向迭代器
for (i = v.begin(); i != v.end(); ++i) { //用迭代器遍历容器
cout << *i << " "; //*i 就是迭代器i指向的元素
*i *= 2; //每个元素变为原来的2倍
}
cout << endl;
//用反向迭代器遍历容器
for (vector<int>::reverse_iterator j = v.rbegin(); j != v.rend(); ++j)
cout << *j << " ";
return 0;
}
程序的输出结果是:
0 1 2 3 4
8 6 4 2 0
后置++
要多生成一个局部对象 tmp,因此执行速度比前置的慢
。同理,迭代器是一个对象,STL 在重载迭代器的++运算符时,后置形式也比前置形式慢
。在次数很多的循环中,++i和i++可能就会造成运行时间上可观的差别了。因此,本教程在前面特别提到,对循环控制变量i,要养成写++i
、不写i++
的习惯。
注意,容器适配器 stack
、queue
和 priority_queue
没有迭代器。容器适配器有一些成员函数
,可以用来对元素进行访问。
迭代器的功能分类
不同容器的迭代器,其功能强弱有所不同。容器的迭代器的功能强弱,决定了该容器是否支持 STL 中的某种算法。例如,排序算法需要通过随机访问迭代器来访问容器中的元素,因此有的容器就不支持排序算法。
常用的迭代器按功能强弱分为输入、输出、正向、双向、随机访问五种,这里只介绍常用的三种
。
正向迭代器
。假设 p是一个正向迭代器,则p支持以下操作:++p
,p++
,*p
。此外,两个正向迭代器可以互相赋值,还可以用==
和!=
运算符进行比较。双向迭代器
。双向迭代器具有正向迭代器的全部功能。除此之外,若 p 是一个双向迭代器,则--p
和p--
都是有定义的。--p
使得 p朝和++p
相反的方向移动。- 随机访问迭代器。随机访问迭代器具有双向迭代器的全部功能。若 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:
p+=i
:使得 p 往后移动 i 个元素。p-=i
:使得 p 往前移动 i 个元素。p+i
:返回 p 后面第 i 个元素的迭代器。p-i
:返回 p 前面第 i 个元素的迭代器。p[i]
:返回 p 后面第 i 个元素的引用。
此外,两个随机访问迭代器 p1、p2 还可以用 <、>、<=、>= 运算符进行比较。p1<p2
的含义是:p1 经过若干次(至少一次)++
操作后,就会等于 p2。其他比较方式的含义与此类似。
对于两个随机访问迭代器 p1、p2,表达式p2-p1
也是有定义的,其返回值是 p2 所指向元素和 p1 所指向元素的序号之差
(也可以说是 p2 和 p1 之间的元素个数减一)。
表1所示为不同容器的迭代器的功能。
容器 | 迭代器功能 |
---|---|
vector | 随机访问 |
deque | 随机访问 |
list | 双向 |
set / multiset | 双向 |
map / multimap | 双向 |
stack | 不支持迭代器 |
queue | 不支持迭代器 |
priority_queue | 不支持迭代器 |
迭代器的辅助函数
STL 中有用于操作迭代器的三个函数模板,它们是:
advance(p, n)
:使迭代器 p 向前或向后移动 n 个元素。distance(p, q)
:计算两个迭代器之间的距离,即迭代器 p 经过多少次 + + 操作后和迭代器 q 相等。如果调用时 p
已经指向 q 的后面,则这个函数会陷入死循环
。iter_swap(p, q)
:用于交换两个迭代器 p、q指向的值
。
要使用上述模板,需要包含头文件 algorithm。下面的程序演示了这三个函数模板的 用法.
#include <list>
#include <iostream>
#include <algorithm> //要使用操作迭代器的函数模板,需要包含此文件
using namespace std;
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
list <int> lst(a, a+5);
list <int>::iterator p = lst.begin();
advance(p, 2); //p向后移动两个元素,指向3
cout << "1)" << *p << endl; //输出 1)3
advance(p, -1); //p向前移动一个元素,指向2
cout << "2)" << *p << endl; //输出 2)2
list<int>::iterator q = lst.end();
q--; //q 指向 5
cout << "3)" << distance(p, q) << endl; //输出 3)3
iter_swap(p, q); //交换 2 和 5
cout << "4)";
for (p = lst.begin(); p != lst.end(); ++p)
cout << *p << " ";
return 0;
}
程序的输出结果是:
1) 3
2) 2
3) 3
4) 1 5 3 4 2
pair
pair将两个数据(经常为不同数据类型)组合成一组数据。
pair的实现是一个结构体
,主要的两个成员变量是first
、second
。
pair的常见构造方法
1.pair<T1, T2> p1
;
创建一个空的pair对象,它的两个元素分别是T1和T2类型,然后赋值初始化。实例如下
#include<bits/stdc++.h>
using namespace std;
int main() {
pair<int,double> p1;
p1.first=1;
p1.second=2.5;
cout<<p1.first<<" "<<p1.second<<endl;
return 0;
}
输出为:1 2.5
2.pair<T1, T2> p1(v1, v2);
创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1
,second成员初始化为v2
。实例如下:
#include<bits/stdc++.h>
using namespace std;
int main() {
pair<string, double> p2("Algorithm", 56.8);
cout<<p2.first<<" "<<p2.second<<endl;
return 0;
}
输出为:Algorithm 56.8
3.make_pair(v1, v2);
以v1和v2的值创建一个新的pair对象
,其元素类型分别是v1和v2的类型。实例如下
#include<bits/stdc++.h>
using namespace std;
int main(){
int age=8;
string name="James";
pair<int,string> p3;
p3=make_pair(age,name);
cout<<p3.first<<" "<<p3.second<<endl;
return 0;
}
输出为:8 James
优先队列priority_queue
优先队列priority_queue,本质上是用堆
实现的,可用于实现堆优化的Dijkstra算法
。
基本语法
- 升序队列,
小根堆
:priority_queue <int,vector<int>,greater
<int> > p; - 降序队列,
大根堆
:priority_queue <int,vector<int>,less
<int> >q; - 对于基础数据类型,
默认是大顶堆
:priority_queue r; //等同于 priority_queue<int,vector, less > r;
基本操作
优先队列priority_queue
和队列
基本操作相同:
top
访问队头元素empty
队列是否为空size
返回队列内元素个数push
插入元素到队尾 (并排序)emplace
原地构造一个元素并插入队列pop
弹出队头元素swap
交换内容
优先队列priority_queue的常见实现如下:
#include<bits/stdc++.h>
using namespace std;
int main(){
priority_queue<int> a;
priority_queue<int,vector<int>,greater<int> > b;
priority_queue<string> c;
for (int i=0;i<5;i++){
a.push(i);
b.push(i);
}
while (!a.empty()){
cout<<a.top()<<" ";
a.pop();
}
cout<<endl;
while(!b.empty()){
cout<<b.top()<<" ";
b.pop();
}
cout<<endl;
c.push("abc");
c.push("abcd");
c.push("cbd");
while (!c.empty()){
cout<<c.top()<<" ";
c.pop();
}
cout<<endl;
return 0;
}
输出为:
4 3 2 1 0
0 1 2 3 4
cbd abcd abc
#include<bits/stdc++.h>
using namespace std;
int main() {
priority_queue<pair<int, int> > a;
pair<int,int> b(1,5);
pair<int,int> d(1,2);
pair<int,int> c(6,1);
a.push(d);
a.push(c);
a.push(b);
while (!a.empty()) {
cout<<a.top().first<<" "<<a.top().second<<endl;
a.pop();
}
return 0;
}
【程序输出】
pair的比较规则:先比较第一个元素,第一个相等比较第二个。
6 1
1 5
1 2