一.STL基本概念
1.STL基本概念
-- STL(standard template library,标准模板库)
-- STL从广义上分为:容器(container) 算法(algorithm) 迭代器(iterator)
-- 容器 和 算法 之间通过 迭代器 进行无缝连接
-- STL几乎所有的代码都采用了模板类或者模板函数
2.STL六大组件
分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据
算法:各种常用的算法,如sort、find、copy、for_each等
迭代器:扮演了容器和算法之间胶合剂
仿函数:行为类似函数,可作为算法的某种策略
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
空间配置器:负责空间的配置和管理
3.STL中的容器、算法、迭代器
1.容器:STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组、链表、树、栈、队列、集合、映射表等
容器分为:序列式容器和关联式容器
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
2.算法:有限的步骤,解决逻辑或数学上的问题,这一门学科叫做算法(algorithms)
算法分为:质变算法和非质变算法
质变算法:运算过程中会更改区间内的元素的内容,如拷贝、替换、删除等
非质变算法:运算过程中不会更改区间内的元素的内容,如查找、计数、遍布等
3.迭代器:容器和算法之间的粘合剂,提供一种方法,使之能够依序访问某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段可以先理解迭代器为指针
迭代器种类:
常用的容器中迭代器种类为双向迭代器和随机访问迭代器。
4.容器算法迭代器初识
如下,使用迭代器遍历v1
void test() {
//创建一个vector容器
vector<int> v1;
//向容器中插入数据
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v1.begin();//起始迭代器,指向容器中第一个元素
vector<int>::iterator itEnd = v1.end();//结束迭代器,指向容器中最后一个元素的下一个位置
//第一种遍历方式
while (itBegin != itEnd) {
cout << *itBegin << endl;
itBegin++;
}
//第二种遍历方式
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << endl;
}
}
二.常用容器
1.string容器
1.1基本概念
本质: string是C++风格的字符串,本质上是一个类
string与char*的区别:
-- char*是一个指针
-- string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器
特点:
string类内部封装了很多成员方法,如查找find、拷贝copy等
string管理char*所分配的内存,不用担心复制越界和取值越界,由类内部进行负责
1.2string构造函数
构造函数原型:
string(); //创建一个空的字符串,如string s;
string(const char* s); //使用字符串s初始化;
string(const string& s); //使用一个string对象初始化另一个string对象
string(const string& s, int begin, int len);//将字符串s从下标begin开始、长度为len的部分作为字符串初值
string(int n, char c); //使用n个字符c初始化
示例:
string s1; //生成空字符串
string s2("12345"); //生成"12345"的复制品
string s3("12345", 0, 3); //结果为"123"
string s4(5, '1'); //结果为"11111"
string的多种构造函数没有可比性,灵活使用即可
1.3string赋值操作
功能:给string字符串赋值
函数原型:
string& operator=(const char* s); //char*类型字符串赋值给当前字符串
string& operator=(const string& s); //把字符串s赋值给当前字符串
string& assign(const char* s); //把字符串s赋值给当前字符串
string& assign(const char* s,int n); //把字符串s的前n个字符赋值给当前字符串
string& assign(const string& s); //
string& assign(int n,char c); //用n个字符c赋值给当前字符串
string的赋值方式有很多,=是比较实用的
1.4string的大小和容量
功能:获取对象的大小和容量
函数原型:
int size()
int length()
//返回string对象的字符个数,他们执行效果相同。
int capacity()//重新分配内存之前,string对象能包含的最大字符数
示例:
string s("1234567");
cout << s.size() << endl; //输出7
cout << s.length() << endl; //输出7
cout << s.capacity() << endl; //输出15
1.5string字符串拼接
功能:实现在字符串末尾拼接字符串
函数原型:
string& operator+=(const char* s);
string& operator+=(const string& s);
string& append(const char* s);
string& append(const char* s, int n); //把字符串s的前n个字符连接到当前字符串末尾
string& append(const string& s);
string& append(const string& s, int pos, int n); //把字符串s从pos开始的n个字符连接到当前字符串末尾
1.6string查找和替换
功能:
-- 查找:查找指定字符串是否存在
-- 替换:在指定的位置替换字符串
函数原型:
int find(const string& s, int pos=0) const; //查找字符串s第一次出现的位置,从pos开始找
int find(const string& s, int pos=0, int n) const;//从pos位置查找字符串s的前n个字符第一次出现的位置
int find(const char c, int pos=0) const; //查找字符c第一次出现的的位置
int rfind(const string& 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& s); //替换从pos开始的n个字符为字符串s
示例:
string s1 = "11abc11";
cout << s1.find("11")<<endl; //输出0
cout << s1.rfind("11") << endl; //输出5
string s2 = "aabbccdd";
s2.replace(2, 2, "1111");
cout << s2 << endl; //输出aa1111ccdd
-- find查找是从左往右,rfind是从右往左
-- find找不到则返回一个很大的数,表示找不到,在无穷远
1.7字符串比较
功能:字符串之间的比较
比较方式:按照字符的ASCII码比较
= 返回 0 > 返回 1 < 返回 -1
函数原型:
int compare(const string& s) const;//与字符串s比较
示例:
string s1 = "aa";
string s2 = "ab";
cout << s1.compare(s2)<<endl; //输出-1
1.8string字符存取
功能:对单个字符进行读或写的操作
char& operator[](int n); //通过[]获取字符
char& at[](int n); //通过at获取字符
1.9string插入和删除
功能:对字符串进行插入和删除字符操作
函数原型:
string& insert(int pos, const string& s); //插入字符串
string& insert(int pos, int n, char c); //在指定位置插入n个字符c
string& erase(int pos, int n=npos); //删除从pos开始的n个字符
示例:
string s1 = "12345";
s1.insert(1, "000");
cout << s1 << endl; //输出10002345
string s2 = "12345";
s2.erase(1);
cout << s2 << endl; //输出1
插入和删除的起始下标都是从0开始的
1.10string子串
函数原型:
string substr(int pos=0, int n=npos)const;//返回由pos开始的n个字符组成的字符串
示例:
string s1 = "12345";
string s2 = s1.substr(1, 3);
cout << s2 << endl; //输出234
2.vector容器
2.1基本概念
功能:与数组非常相似,也称为单端数组
与普通数组的区别:数组是静态空间,而vector可以动态扩展
动态扩展:并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝至新空间,释放原空间
vector容器的迭代器是支持随机访问的迭代器,即它的迭代器可以跳跃式的访问
2.2vector构造函数
功能:创建一个vector容器
函数原型:
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(),v.end()); //将v[ begin(),end() )区间中的元素拷贝给本身(区间前闭后开)
vector(n,elem); //构造函数将n个elem拷贝给本身
vector(const vector& v); //拷贝构造函数
示例:
//vector<int> 输出
void Print_vector_int(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << ' ';
}
cout << endl;
}
//vector构造
void test01() {
vector<int> v1; //默认构造
//向容器中插入数据
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
Print_vector_int(v1);
//输出1 2 3 4 5
vector<int> v2(v1.begin(), v1.end());//通过区间方式构造
Print_vector_int(v2);
//输出1 2 3 4 5
vector<int> v3(5, 1);//n个elem方式构造
Print_vector_int(v3);
//输出1 1 1 1 1
vector<int> v4(v3);//拷贝构造
Print_vector_int(v4);
//输出1 1 1 1 1
}
2.3vector赋值操作
功能:给vector容器进行赋值
函数原型:
vector& operator=(const vector& v); //重载等号运算符
assign (begin, end); //将[begin,end)区间中的数据拷贝赋值给本身
assign (n, elem); //将n个elem拷贝赋值给本身
示例:
//vector赋值
void test02() {
vector<int> v1; //默认构造
//向容器中插入数据
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
vector<int> v2 = v1;//等号赋值
Print_vector_int(v2);
//输出1 2 3 4 5
vector<int> v3;
v3.assign(v1.begin(), v1.end());
Print_vector_int(v3);
//输出1 2 3 4 5
}
2.4vector容量和大小
功能:对vector容器的容量和大小操作
函数原型:
empty(); //判断容器是否为空
capacity(); //容器的容量
size(); //返回容器中元素的个数
resize(int num); //重新指定容器的长度为num,
//若容器变长,则以默认值填充新位置,
//若容器变短,则末尾超出容器长度的元素被删除
resize(int num, elem)//同上,以num填充新位置
示例:
//vector的容量和大小
void test03() {
vector<int> v1;
for (int i = 0; i != 10; i++) {
v1.push_back(i);
}
Print_vector_int(v1);
//输出0 1 2 3 4 5 6 7 8 9
if (!v1.empty()) {//若v1不为空
cout << v1.capacity() << endl; //输出13
cout << v1.size() << endl; //输出10
}
//重新指定大小
v1.resize(15);//如果重新指定的比原来长了,默认使用0填充,利用重载版本可以指定填充值
Print_vector_int(v1);
//输出0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
cout << v1.capacity() << endl;//输出19
v1.resize(5);//如果指定的比原来短了,超出部分会删除掉
Print_vector_int(v1);
//输出 0 1 2 3 4
cout << v1.capacity() << endl;//输出19
}
2.5vector插入和删除
功能:对vector容器进行插入和删除
函数原型:
push_back(elem); //尾部插入元素
pop_back(); //删除尾部元素
insert(const_iterator pos, elem); //迭代器指向位置pos插入元素elem
insert(const_iterator pos, int count, elem);//迭代器指向位置pos插入count个元素elem
erase(const_iterator); //删除迭代器指向的元素
erase(const_iterator start, const_iterator end);//删除[start,end)区间的元素
clear(); //删除容器中所有元素
示例:
void test04() {
vector<int> v1;
for (int i = 0; i != 10; i++) {
v1.push_back(i); //push_back尾插
}
Print_vector_int(v1);
//输出0 1 2 3 4 5 6 7 8 9
v1.pop_back(); //pop_back尾删,删去9
v1.insert(v1.begin(), 100); //insert插入
Print_vector_int(v1);
//输出100 0 1 2 3 4 5 6 7 8
v1.erase(v1.begin());//erase删除
Print_vector_int(v1);
//输出 0 1 2 3 4 5 6 7 8
v1.erase(v1.begin(), v1.end());//erase清空
v1.clear();//clear清空
}
2.6vector数据存取
功能:对vector中的数据进行存取操作
函数原型:
at(int index); //返回索引index所指的数据
operator[] (int index); //返回索引index所指的数据
front(); //返回容器中的第一个数据元素
back(); //返回容器中的最后一个数据元素
示例:
//数据存取
void test05() {
vector<int> v1;
for (int i = 0; i != 10; i++) {
v1.push_back(i); //push_back尾插
}
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << ' ';//输出 0 1 2 3 4 5 6 7 8 9
}
cout << endl;
for (int i = 0; i < v1.size(); i++) {
cout << v1.at(i) << ' ';//输出 0 1 2 3 4 5 6 7 8 9
}
cout << endl;
cout << v1.front() << endl;//输出0
cout << v1.back() << endl;//输出9
}
2.7vector互换容器
功能:实现两个容器对象内元素互换
函数原型:
swap(vec);//将vec与自己本身的元素互换
swap互换的两个对象不仅值互换,capacity值也会互换
示例:
//互换容器
void test06() {
vector<int> v1,v2;
for (int i = 0; i != 5; i++) {
v1.push_back(i+1);
}
for (int i = 0; i != 10; i++) {
v2.push_back(i+1);
}
Print_vector_int(v1);//输出1 2 3 4 5
Print_vector_int(v2);//输出1 2 3 4 5 6 7 8 9 10
cout << v1.capacity()<<endl;//输出6
cout << v2.capacity()<<endl;//输出13
v1.swap(v2);//互换容器
Print_vector_int(v1);//输出1 2 3 4 5 6 7 8 9 10
Print_vector_int(v2);//输出1 2 3 4 5
cout << v1.capacity() << endl;//输出13
cout << v2.capacity() << endl;//输出6
}
巧用swap可以收缩内存空间
//巧用swap收缩内存
void test() {
vector<int> v3;
for (int i = 0; i != 10000; i++) {
v3.push_back(i + 1);
}
cout << v3.capacity() << endl; //输出12138
cout << v3.size() << endl; //输出10000
v3.resize(5);
cout << v3.capacity() << endl; //输出12138
cout << v3.size() << endl; //输出5
//收缩内存
vector<int>(v3).swap(v3);//拷贝构造创建一个匿名对象,但创建的匿名的capacity值只有5,然后swap,之后匿名对象自动销毁
cout << v3.capacity() << endl;//输出5
cout << v3.size() << endl;//输出5
}
2.8vector预留空间
功能:减少vector在动态扩展容量时的扩展次数
如果提前知道数据量较大,可以一开始利用reserve预留空间
函数原型:
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问
示例:
//容器预留空间
void test07() {
vector<int> v1;
int count = 0;//统计一共动态开辟了多少次内存
int* p = nullptr;
for (int i = 0; i < 100000; i++) {
v1.push_back(i);
if (p != &v1[0]) {//动态开辟一次内存,count+一次
++count;
p = &v1[0];
}
}
cout << count << endl;//输出30,即动态开辟了29次
vector<int> v2;
count = 0;
p = nullptr;
v2.reserve(100000);
for (int i = 0; i < 100000; i++) {
v2.push_back(i);
if (p != &v2[0]) {//动态开辟一次内存,count+一次
++count;
p = &v2[0];
}
}
cout << count << endl;//输出1,即动态开辟了0次
}
3.deque容器
3.1基本概念
功能:双端数组,可以对头端和尾端进行插入删除操作
deque与vector的区别:
-- vector对于头部的插入删除效率太低,数据量越大,效率越低。deque相对而言,对头部的插入 删除速度会比vector快
-- vector访问元素时的速度回避deque快,这与两者的内部实现有关
deque内部原理:
deque内部有一个中控器,维护每段缓冲区的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
vector容器的迭代器是支持随机访问的迭代器,即它的迭代器可以跳跃式的访问
3.2deque构造函数
功能:deque容器构造
函数原型:
deque<T> d; //采用模板实现类实现,默认构造函数
deque(d.begin(),d.end()); //将d[ begin(),end() )区间中的元素拷贝给本身(区间前闭后开)
deque(n,elem); //构造函数将n个elem拷贝给本身
deque(const deque& d); //拷贝构造函数
示例:
//打印deque
void printDeque(const deque<int>& d) {
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << ' ';
}
cout << endl;
}
void test08() {
deque<int> d(5, 10);
printDeque(d);
//输出10 10 10 10 10
}
3.3deque赋值操作
功能:给deque容器进行赋值
函数原型:
deque& operator=(const deque& d); //重载等号运算符
assign(beg,end); //将[beg,end)区间中的数据拷贝赋值给自身
assign(n,elem); //将n个elem拷贝赋值给自身
3.4deque大小操作
功能:对deque容器的大小进行操作
函数原型:
empty(); //判断容器是否为空
size(); //返回容器中元素的个数
resize(int num); //同vector的resize
resize(int num, elem);
deque无capacity。
3.5deque插入和删除
功能:向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,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值
clear(); //清空容器的所有数据
erase(beg,end); //删除[beg,end)区间的数据,返回下一个元素的地址
erase(pos); //删除pos位置的数据,返回下一个数据的地址
3.6deque数据存取
功能:对deque中的数据进行存取
函数原型:
at(int index); //返回索引index所指的数据
operator[] (int index); //返回索引index所指的数据
front(); //返回容器中的第一个数据元素
back(); //返回容器中的最后一个数据元素
3.7deque排序
利用算法实现对deque容器进行排序
算法:
使用时需要包含头文件algorithm
sort(iterator beg,iterator end);//对beg和end区间内元素进行排序
示例:
//deque排序
void test09() {
deque<int> d;
d.push_back(1);//尾插
d.push_back(2);
d.push_back(3);
d.push_front(10);//头插
d.push_front(20);
d.push_front(30);
printDeque(d);
//输出30 20 10 1 2 3
//对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序
sort(d.begin(), d.end());//默认升序排序
printDeque(d);
//输出1 2 3 10 20 30
}
对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序
4.stack容器
4.1基本概念
概念:stack是一种先进后出(First In Last Out,FILO)的数据结构,他只有一个开口
栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为
栈中进入元素为--入栈--push
栈中弹出元素为--出栈-pop
4.2stack常用接口
功能:栈容器常用的对外接口
函数原型:
//构造函数
stack<T> stk; //默认构造函数
stack(const stack& stk>; //拷贝构造函数
//赋值操作
stack& operator= (const stack& stk);//重载等号运算符
//数据存取
push(elem); //向栈顶添加一个元素
pop(); //从栈顶移除一个元素
top(); //返回栈顶元素
//大小操作
empty(); //判断栈是否为空
size(); //返回栈的大小
5.queue容器
5.1基本概念
概念:queue是一种先进先出的数据结构,他有两个开口
队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头和队尾才可以被外界使用,因此队列不允许有便利行为
队列中进元素称为--入队--push
队列中出元素称为--出队--pop
5.2queue常用接口
功能:队列容器常用的对外接口
函数原型:
//构造函数
queue<T> que; //默认构造
queue(const queue& que); //拷贝构造
//赋值操作
queue& operator= (const queue& que);//重载等号运算符
//数据存取
push(elem); //在队尾添加一个元素
pop(); //从对头删除一个元素
back(); //返回最后一个元素
front(); //返回第一个元素
//大小操作
empty(); //判断队列是否为空
size(); //返回队列的大小
6.list容器
6.1基本概念
功能:将数据进行链式存储
STL中的链表是一个双向循环链表
由于链表的存储方式并不是连续的内存空间,因此list的迭代器只支持前移和后移,属于双向迭代器
list的优点:
-- 采用动态存储分配,不会造成内存浪费和溢出
-- 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
-- 链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大
List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的
STL中list和vector是两个最常用的容器,各有优缺点
6.2list构造函数
函数原型:
liSt<T> lst; //默认构造
list(beg, end); //将[beg,end)区间中的元素拷贝给本身
list(n, elem); //将n个elem拷贝给本身
list(const list& lst); //拷贝构造函数
6.3list赋值和交换
功能:给list容器进行赋值,以及交换list容器
函数原型:
list& operator= (const list& lst);//重载等号运算符
assign(beg, end);
assign(n,elem);
swap(lst); //将lst与本身的元素互换
6.4list大小操作
功能:对list容器的大小进行操作
函数原型:
size(); //返回容器中元素的个数
empty(); //判断容器是否为空
resize(num); //同vector的resize
resize(num, elem);
6.5list插入和删除
功能:对list容器进行数据的插入和删除
函数原型:
push_back(elem); //在容器尾部插入一个元素
pop_back(); //从容器尾部删除一个元素
push_front(elem); //在容器头部插入一个元素
pop_front(); //从容器头部删除一个元素
insert(pos, elem); //在pos位置插入elem元素的拷贝,返回新元素的地址
insert(pos, n, elem); //在pos位置插入n个elen元素,无返回值
insert(pos, beg, end); //在pos位置插入[beg,end)区间的元素,无返回值
clear(); //移除容器的所有数据
erase(beg,end); //删除[beg,end)区间的数据,返回下一个元素的位置
erase(pos); //删除pos位置的元素,返回下一个元素的位置
remove(elem); //删除容器中所有值与elem值匹配的元素
6.6list数据存取
功能:对list容器中数据进行存取
函数原型:
front(); //返回第一个元素
back(); //返回最后一个元素
list并不支持 [ ] 和 at 的方式访问,且list的迭代器不支持随机访问,只支持前移和后移,属于双向迭代器。
6.7list反转和排序
功能:将容器中的元素反转,以及将容器中的数据进行排序
函数原型:
reverse(); //反转链表
sort(); //链表排序
示例:
bool mycompareInt(int n1, int n2) {
return n1 > n2;
}
//list反转和排序
void test10() {
list<int> l;
l.push_back(1);
l.push_back(3);
l.push_back(2);
l.push_back(5);
l.push_back(4);
print_list_int(l);
//输出1 3 2 5 4
//所有不支持随机访问迭代器的容器,不可以使用标准算法
//不支持随机访问迭代器的容器,内部会提供一些算法
l.reverse();//反转链表
print_list_int(l);
//输出4 5 2 3 1
l.sort();//排序链表,默认排序 从小到大
print_list_int(l);
//输出1 2 3 4 5
l.sort(mycompareInt);//从大到小
print_list_int(l);
//输出5 4 3 2 1
}
所有不支持随机访问迭代器的容器,不可以使用标准算法
不支持随机访问迭代器的容器,内部会提供一些算法
7.set/multiset容器
7.1基本概念
简介:所有元素会在插入时自动被排序
本质:属于关联式容器,底层结构是用二叉树实现
set与multiset区别:
--set不允许有重复元素
--multiset允许有重复元素
7.2set构造和赋值
功能:创建set容器以及赋值
函数原型:
//构造
set<T> s; //默认构造函数
set(const set& s); //拷贝构造函数
//赋值
set& operator=(const set& s);//重载等号运算符
7.3set大小和交换
功能:统计set容器大小及交换set容器
函数原型:
size(); //返回容器中元素个数
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
7.4set插入和删除
功能:set容器进行插入数据和删除数据
函数原型:
insert(elem); //在容器插入元素
clear(); //清空容器
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem); //删除容器中值为elem的元素
7.5set查找和统计
功能:对set容器进行查找元素以及统计元素
函数原型:
find(key); //查找key是否存在,若存在,返回该元素的迭代器,若不存在,返回set.end();
count(key); //统计key的元素个数
7.6set和multiset区别
区别:
-- set不可以插入重复数据,而multiset可以
-- set插入数据的同时会返回插入结果,表示是否插入成功
-- multiset不会检测数据,因此可以插入重复数据
7.7pair对组创建
功能:成对出现的数据,利用对组可以返回两个数据
创建方式:
//1
pair<type1, type2> p (value1, value2);
//2
pair<type1, type2> p = make_pair(value1, value2);
要想访问对组中的数据,可以直接
对象名.first访问第一个元素
对象名.second访问第二个元素
7.8内置数据类型指定排序规则
目标:set容器默认排序规则为从小到大,掌握如何改变排序规则
技术点:利用仿函数,可以改变排序规则
示例:设置set从大到小排序
//仿函数int从大到小
class mycompare1 {
public:
bool operator() (int n1, int n2)const {
return n1 > n2;
}
};
//set容器内置数据类型指定排序规则
void test11() {
set<int> s1;
s1.insert(4);
s1.insert(2);
s1.insert(1);
s1.insert(5);
s1.insert(3);
for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
cout << *it << ' ';
}
cout << endl;
//输出1 2 3 4 5
set<int,mycompare1> s2;
s2.insert(4);
s2.insert(2);
s2.insert(1);
s2.insert(5);
s2.insert(3);
for (set<int,mycompare1>::iterator it = s2.begin(); it != s2.end(); it++) {
cout << *it << ' ';
}
cout << endl;
//输出5 4 3 2 1
}
7.9自定义数据类型指定排序规则
示例:
class Person {
public:
Person(string n, int a) {
this->name = n;
this->age = a;
}
string name;
int age;
};
class mycompare2 {
public:
bool operator() (const Person& p1, const Person& p2)const {
return p1.age > p2.age;
}
};
//set容器自定义数据类型指定排序规则
void test12() {
set<Person,mycompare2> s1;
Person p1("张三", 18);
Person p2("李四", 19);
Person p3("王五", 20);
s1.insert(p1);
s1.insert(p2);
s1.insert(p3);
for (set<Person, mycompare2>::iterator it = s1.begin(); it != s1.end(); it++) {
cout << (*it).name << (*it).age << ' ';
cout << endl;
}
cout << endl;
//输出 "王五", 20
//输出 "李四", 19
//输出 "张三", 18
}
8.map/multimap容器
8.1基本概念
简介:
-- map中所有元素都是pair
-- pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
-- 所有元素都会根据元素的键值自动排序
本质:
map/multimap属于关联式容器,底层结构是用二叉树实现
优点:
-- 可以根据key值快速找到value值
map与multimap区别为map不允许容器中有重复key值元素,二multimap允许
8.2map构造和赋值
功能:对map容器进行构造和赋值操作
函数原型:
map<T1, T2> mp; //默认构造
map(const map& mp); //拷贝构造
示例:
void test13() {
map<int, int> m1;
//插入数据
m1.insert(make_pair(3, 30));//利用make_pair插入
m1.insert(make_pair(4, 40));
m1.insert(pair<int, int>(1, 10));//创建匿名对组插入
m1.insert(pair<int, int>(2, 20));
for (map<int, int>::iterator it = m1.begin(); it != m1.end(); it++) {
cout << "key: " << it->first << " value: " << it->second << endl;
}
//输出 key: 1 value: 10
//输出 key: 2 value : 20
//输出 key : 3 value : 30
//输出 key : 4 value : 40
}
注意:map中所有元素都是成对出现,插入数据时需要使用对组
8.3map大小和交换
功能:统计map容器大小以及交换map容器
函数原型:
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(mp); //交换两个map容器
8.4map插入和删除
功能:map容器进行插入数据和删除数据
函数原型:
insert(elem); //插入元素,看下图示例
clear(); //清空容器
erase(pos); //删除pos迭代器所指的元素,并返回下一个元素的迭代器
erase(key); //删除容器中 键值为key 的元素
示例:
//map插入和删除
void test14() {
map<int, int> m1;
//插入数据
// 1
m1.insert(pair<int, int>(1, 10));
// 2
m1.insert(make_pair(2, 20));
// 3
m1.insert(map<int, int>::value_type(3, 30));
// 4
m1[4] = 40;
// [ ]不建议用来插入,可以用来利用key访问value,如 cout << m1[3]; 输出30
//若利用 [ ]来访问不存在的key,会自动插入(key, 0) ,如 cout << m1[44]; 输出0
for (map<int, int>::iterator it = m1.begin(); it != m1.end(); it++) {
cout << "key: " << it->first << " value: " << it->second << endl;
}
//输出 key: 1 value: 10
//输出 key: 2 value: 20
//输出 key: 3 value: 30
//输出 key: 4 value: 40
//删除
m1.erase(2);//根据key删除元素
for (map<int, int>::iterator it = m1.begin(); it != m1.end(); it++) {
cout << "key: " << it->first << " value: " << it->second << endl;
}
//输出 key: 1 value: 10
//输出 key: 3 value: 30
//输出 key: 4 value: 40
}
8.5map查找和统计
功能:对map容器进行查找元素以及统计元素
函数原型:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回map.end();
count(key); //统计key的元素个数
示例:
void test15() {
map<int, int> m1;
//插入数据
m1.insert(make_pair(1, 10));
m1.insert(make_pair(2, 20));
m1.insert(make_pair(3, 30));
map<int, int>::iterator pos = m1.find(2);
if (pos != m1.end()) {
cout << "已找到元素" << endl;
cout << "key: " << pos->first << " value: " << pos->second << endl;
}
else {
cout << "未找到元素" << endl;
}
//输出 已找到元素
//输出 key: 2 value: 20
pos = m1.find(111);
if (pos != m1.end()) {
cout << "已找到元素" << endl;
cout << "key: " << pos->first << " value: " << pos->second << endl;
}
else {
cout << "未找到元素" << endl;
}
//输出 未找到元素
}
注意:find返回的是迭代器
8.6map排序
技术点:利用仿函数,改变排序规则
示例:
//仿函数int从大到小
class mycompare1 {
public:
bool operator() (int n1, int n2)const {
return n1 > n2;
}
};
//map改变排序规则
void test16() {
//利用仿函数改变排序规则
map<int, int, mycompare1> m1;
//插入数据
m1.insert(make_pair(1, 10));
m1.insert(make_pair(2, 20));
m1.insert(make_pair(3, 30));
for (map<int, int>::iterator it = m1.begin(); it != m1.end(); it++) {
cout << "key: " << it->first << " value: " << it->second << endl;
}
//输出 key: 3 value: 30
//输出 key: 2 value: 20
//输出 key: 1 value: 10
}
三.函数对象(仿函数)
1.函数对象
1.1函数对象概念
概念:
-- 重载函数调用操作符的类,其对象常称为函数对象
-- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:
函数对象(仿函数)是一个类,不是一个函数
1.2函数对象使用
特点:
-- 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
-- 函数对象超出普通函数的概念,函数对象可以有自己的状态
-- 函数对象可以作为参数传递
//函数对象(仿函数)调用
class myPrint {
public:
void operator() (string text) {
cout << text << endl;
}
};
void test18() {
myPrint m1;
m1("hello world");
//输出hello world
}
2.谓词
2.1谓词概念
概念:
-- 返回bool类型的仿函数称为谓词
-- 如果operator()接受一个参数,叫做一元谓词
-- 如果operator()接受两个参数,叫做二元谓词
2.2一元谓词
示例:
//一元谓词
//大于5为真
class GreaterFive {
public:
bool operator() (int n) {
return n > 5;
}
};
void test19() {
vector<int> v1;
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
vector<int>::iterator it;
//GreaterFive()为匿名的函数对象
it = find_if(v1.begin(), v1.end(), GreaterFive());
cout << *it << endl;
//输出6
}
提示:在谓词类里加一个有参构造,就可以随意控制大于或小于几的条件,就不用重复写谓词
2.3二元谓词
示例:
//仿函数int从大到小
class mycompare1 {
public:
bool operator() (int n1, int n2)const {
return n1 > n2;
}
};
//二元谓词
//从大到小排序
void test20() {
vector<int> v1;
v1.push_back(4);
v1.push_back(3);
v1.push_back(2);
v1.push_back(1);
v1.push_back(5);
//sort默认从小到大
sort(v1.begin(), v1.end());
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << ' ';
}
cout << endl;
//输出1 2 3 4 5
//mycompare1()为匿名函数对象
sort(v1.begin(), v1.end(), mycompare1());
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << ' ';
}
cout << endl;
//输出5 4 3 2 1
}
3.内建函数对象
3.1内建函数对象意义
概念:
-- STL内建了一些函数对象
分类:
-- 算术仿函数
-- 关系仿函数
-- 逻辑仿函数
用法:
-- 这些仿函数所产生的对象,用法和一般函数完全相同
-- 使用内建函数对象,需要引入头文件<functional>
3.2算术仿函数
功能:实现四则运算,其中negate是一元运算,其他都是二元运算
仿函数原型:
template<class T> T plus<T> //加法仿函数
template<class T> T minus<T> //减法仿函数
template<class T> T multiplies<T> //乘法仿函数
template<class T> T divides<T> //除法仿函数
template<class T> T modulus<T> //取模仿函数
template<class T> T negate<T> //取 相反数 仿函数
示例:
//算术仿函数
void test21() {
//一元仿函数,取反
negate<int> n;
cout << n(100) << endl;
//输出-100
//二元仿函数,相加
plus<int> p;
cout << p(100, 200) << endl;
//输出300
}
3.3关系仿函数
功能:实现关系对比
仿函数原型:
template<class T> bool equal_to<T>; //等于
template<class T> bool not_equal<T>; //不等于
template<class T> bool greater<T>; //大于
template<class T> bool greater_equal<T>; //大于或等于
template<class T> bool less<T>; //小于
template<class T> bool less_equal<T>; //小于或等于
示例:
//关系仿函数
void test22() {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//传入匿名对象
sort(v.begin(), v.end(), greater<int>());
//或者 greater<int> g;
// sort(v.begin(), v.end(), g);
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << ' ';
}
cout << endl;
//输出5 4 3 2 1
//传入类型
set<int, greater<int>> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
s.insert(5);
for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
cout << *it << ' ';
}
cout << endl;
//输出5 4 3 2 1
}
3.4逻辑仿函数
功能:实现逻辑运算
函数原型:
template<class T> bool logical_and<T>; //逻辑与
template<class T> bool logical_or<T>; //逻辑或
template<class T> bool logical_not<T>; //逻辑非
四.常用算法
概述:
-- 算法主要是由头文件<algorithm> <functional> <numeric>组成
-- <algorithm>是所有STL文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等
-- <numerical>体积很小,只包括几个在序列上面进行简单数学运算的模板函数
-- <functional>定义了一些模板类,用以声明函数对象
1.常用遍历算法
算法简介:
for_each //遍历容器
transform //搬运容器到另一个容器中
1.1for_each
功能:实现遍历容器
函数原型;
for_each(iterator beg, iterator end, _func);
//遍历算法 遍历容器元素
//beg开始迭代器
//end结束迭代器
//_func 函数或函数对象
示例:
//常用遍历算法 for_each
void print01(int v) {
cout << v << ' ';
}
class print02 {
public:
void operator()(int v) {
cout << v << ' ';
}
};
void test23() {
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
//利用普通函数
for_each(v1.begin(), v1.end(), print01);
cout << endl;
//输出1 2 3 4 5
//利用仿函数
for_each(v1.begin(), v1.end(), print02());
cout << endl;
//输出1 2 3 4 5
}
1.2transform
功能:搬运容器到另一个容器中
函数原型:
transform(iterator beg1, iterator end1, iterator beg2, func_);
//beg1 源容器开始迭代器
//end1 源容器结束迭代器
//beg2 目标容器开始迭代器
//func_ 函数或函数对象
示例:
//常用遍历算法 transform
class Transform1{
public:
int operator() (int v) {
return v + 100;
}
};
class print02 {
public:
void operator()(int v) {
cout << v << ' ';
}
};
void test24() {
vector<int> v1; //源容器
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
vector<int>vTarget; //目标容器
vTarget.resize(v1.size());//目标容器需要提前开辟空间
transform(v1.begin(), v1.end(), vTarget.begin(), Transform1());
for_each(v1.begin(), v1.end(), print02());
//输出1 2 3 4 5 即源容器不变
for_each(vTarget.begin(), vTarget.end(), print02());
//输出101 102 103 104 105
}
注意:目标容器需要提前开辟空间,且源容器内元素不变
2.常用查找算法
算法简介:
find //查找元素
find_if //按条件查找元素
adjacent_find //查找相邻重复元素
binary_search //二分查找法
count //统计元素个数
count_if //按条件统计元素个数
2.1find
功能:查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()
函数原型:
find(iterator beg, iterator end, value);
//按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器
//beg 开始迭代器
//end 结束迭代器
//value 查找的元素
示例:
//常用查找算法 find
class Person {
public:
Person(string n, int a) {
this->name = n;
this->age = a;
}
bool operator== (const Person& p) {
if (this->name == p.name && this->age == p.age) {
return true;
}
else return false;
}
string name;
int age;
};
void test25() {
//1.查找内置数据类型
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
//查找 v1 中是否有5这个元素
vector<int>::iterator it1;
it1 = find(v1.begin(), v1.end(), 5);
if (it1 != v1.end()) {
cout << "找到5了"<<endl;
}
else {
cout<<"没有找到5"<<endl;
}
//输出找到5了
//2.查找自定义数据类型
vector<Person> v2;
v2.push_back(Person("张三", 18)); //Person("张三", 18)为匿名对象
v2.push_back(Person("李四", 19));
v2.push_back(Person("王五", 20));
vector<Person>::iterator it2;
it2 = find(v2.begin(), v2.end(), Person("张三", 18));
if (it2 != v2.end()) {
cout << "找到该人员了" << endl;
cout << "姓名:" << (*it2).name << " 年龄:" << (*it2).age << endl;
}
else {
cout << "没有找到该人员"<<endl;
}
//输出 找到该人员了
//输出 姓名:张三 年龄:18
}
注意:查找自定义数据类型,要重载 == 运算符
2.2find_if
功能:按条件查找元素
函数原型:
find_if(iterator beg, iterator end, _Pred);
//按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器
//beg 开始迭代器
//end 结束迭代器
//_Pred 函数或谓词(返回bool类型的仿函数)
2.3adjacent_find
功能:查找相邻重复元素
函数原型:
adjacent_find(iterator beg, iterator end);
//查找相邻重复元素,找到返回相邻元素的第一个位置的迭代器,找不到返回结束迭代器
//beg 开始迭代器
//end 结束迭代器
2.4binary_search
功能:在有序序列中查找指定元素是否存在
函数原型:
binary_search(iterator beg, iterator end, value);
//按值查找元素,找到返回true,找不到返回false
//beg 开始迭代器
//end 结束迭代器
//value 查找的元素
2.5count
功能:统计元素个数
函数原型:
count(iterator beg, iterator end, value);
//统计元素出现的个数
//beg 开始迭代器
//end 结束迭代器
//value 统计的元素
注意:统计自定义数据类型,要重载 == 运算符
2.6count_if
功能:按条件统计元素个数
函数原型:
count_if(iterator beg, iterator end, _Pred);
//按条件统计元素出现的次数
//beg 开始迭代器
//end 结束迭代器
//_Pred 函数或谓词(返回bool类型的仿函数)
3.常用排序算法
算法简介:
sort //对容器内元素进行排序
random_shuffle //洗牌 指定范围内的元素随机调整次序
merge //容器元素合并,并存储到另一个容器中
reverse //反转指定范围的元素
3.1sort
功能:对容器内元素进行排序
函数原型:
sort(iterator beg, iterator end, _Pred);
//beg 开始迭代器
//end 结束迭代器
//_Pred 函数或谓词(返回bool类型的仿函数)默认从小到大
示例:
/常用排序算法
class print02 {
public:
void operator()(int v) {
cout << v << ' ';
}
};
void test26() {
vector<int> v1;
v1.push_back(3);
v1.push_back(1);
v1.push_back(2);
v1.push_back(4);
v1.push_back(5);
//greater<int> 为内建函数对象
sort(v1.begin(), v1.end(), greater<int>());
for_each(v1.begin(), v1.end(), print02());
cout << endl;
//输出5 4 3 2 1
}
3.2random_shuffle
功能:洗牌 指定范围内的元素随机调整次序
函数原型:
random_shuffle(iterator beg, iterator end);
//beg 开始迭代器
//end 结束迭代器
示例:
//常用排序算法
void test26() {
//随机数种子
srand((unsigned int)time(NULL));
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
random_shuffle(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), print02());
cout << endl;
//输出随机序列
}
注意:使用时记得加随机数种子
3.3merge
功能:容器元素合并,并存储到另一个容器中(两个容器必须是有序的)
函数原型:
random_shuffle(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
//两个容器必须是有序的
//beg1 容器1开始迭代器
//end1 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
注意:需要提前给目标容器分配空间,大小为 (size1+size2)
3.4reverse
功能:反转指定范围的元素
函数原型:
reverse(iterator beg, iterator end);
//beg 开始迭代器
//end 结束迭代器
注意: 所有不支持随机访问迭代器的容器,不可以使用标准sort算法
不支持随机访问迭代器的容器,内部会提供一些算法
4.常用拷贝和替换算法
算法简介:
copy //容器内指定范围的元素拷贝到另一个容器
replace //将容器内指定范围的旧元素修改为新元素
replace_if //容器内指定范围满足条件的元素替换为新元素
swap //互换两个容器的元素
4.1copy
功能:容器内指定范围的元素拷贝到另一个容器
函数原型:
copy(iterator beg1, iterator end1, iterator dest);
//两个容器必须是有序的
//beg 容器1开始迭代器
//end 容器1结束迭代器
//dest 目标容器开始迭代器
注意:需要提前给目标容器分配空间
4.2replace
功能:将容器内指定范围的旧元素修改为新元素
函数原型:
replace(iterator beg, iterator end, oldvalue, newvalue);
//beg 容器开始迭代器
//end 容器结束迭代器
//oldvalue 旧元素
//newvalue 新元素
4.3replace_if
功能:容器内指定范围满足条件的元素替换为新元素
函数原型:
replace_if(iterator beg, iterator end, _Pred, newvalue);
//beg 容器开始迭代器
//end 容器结束迭代器
//_Pred 谓词
//newvalue 新元素
4.4swap
功能:互换两个容器的元素
函数原型:
swap(contain c1, contain c2);
//两个容器必须同种类型
//c1 容器1
//c2 容器2
5.常用算术生成算法
算法简介:
accumulate //计算容器元素累计总和
fill //向容器中添加元素
注意:算术生成算法属于小型算法,使用时包含头文件<numeric>
5.1accumulate
功能:计算容器元素累计总和
函数原型:
accumulate(iterator beg, iterator end, value);
//beg 容器开始迭代器
//end 容器结束迭代器
//value 起始累加值,若只算该容器中的总值就将其设为0
5.2fill
功能:后期向容器中填充元素
函数原型:
fill(iterator beg, iterator end, value);
//beg 容器开始迭代器
//end 容器结束迭代器
//value 填充的值
6.常用集合算法
算法简介:
set_intersection //求两个容器的交集
set_union //求两个容器的并集
set_difference //求两个容器的差集
6.1set_intersection
功能:求两个有序容器的交集
函数原型:
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
//beg1 容器1开始迭代器
//end1 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
//返回最后一个交集元素的迭代器
注意:需要提前给目标容器分配空间为 小的size( min(v1.size(),v2.size() )
返回最后一个交集元素的迭代器
6.2set_union
功能:求两个有序容器的并集
函数原型:
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
//beg1 容器1开始迭代器
//end1 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
//返回最后一个并集元素的迭代器
注意:需要提前给目标容器分配空间为 (v1.size() + v2.size() )
返回最后一个并集元素的迭代器
6.3set_difference
功能:求两个有序容器的差集
函数原型:
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
//beg1 容器1开始迭代器
//end1 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
//返回最后一个差集元素的迭代器
注意:需要提前给目标容器分配空间为 v1.size() (第一个参数容器的size)
返回最后一个差集元素的迭代器