琐记1.STL初识
1.1 STL基本概念1.2 STL六大组件1.3 STL中容器、算法、迭代器
1.3.1 容器1.3.2 算法1.3.3 迭代器 1.4容器算法迭代器初识
1.4.1 vector存放内置数据类型1.4.2 vector存放自定义数据类型1.4.3 vector容器嵌套容器 2、STL常用容器
2.1 string容器
2.1.1 string基本概念2.1.2 string构造函数2.1.3 string赋值操作2.1.4 string字符串拼接2.1.5 string查找与替换2.1.6 string字符串的比较2.1.7 string字符存取2.1.8 string插入和删除2.1.8 string子串获取 2.2 vector容器
2.2.1 vector基本概念2.2.2 vector构造函数2.2.3 vector赋值操作2.2.4 vector容量和大小2.2.5 vector插入和删除2.2.6 vector容器数据存取2.2.6 vector互换容器2.2.6 vector预留空间 2.3 deque容器
2.3.1 deque容器基本概念2.3.2 deque构造函数与迭代器2.3.3 deque赋值操作2.3.4 deque大小操作2.3.5 deque插入和删除2.3.6 deque数据存取2.3.7 deque排序 2.4 stack容器
2.4.1 stack基本概念2.4.2 stack常用接口 2.5 queque容器
2.5.1 queque基本概念2.5.2 queque常用接口2.5.3 queque示例 2.6 list
2.6.1 list基本概念2.6.2 list构造函数3.7.3 list赋值和交换3.7.4 list大小操作2.7.5 list插入和删除2.7.6 list 数据存取2.7.7 list 反转和排序2.7.8 list 排序案例 2.8 set/multiset容器
2.8.1 set基本概念2.8.2 set构造和赋值2.8.3 set容器大小和交换2.8.4 set容器插入和删除2.8.5 set查找和统计2.8.6 set和multiset区别2.8.7 pair对组的创建2.8.8 set容器排序 2.9 map/multimap容器
(1) map基本概念(2) map常用函数 琐记 为了准备蓝桥杯不得不学习C++STL部分,这样能够省下来不少的时间;这篇笔记是看B站上黑马程序员的课程的时候记得:
黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
1.STL初识 1.1 STL基本概念STL(Standard Template Library,标准模板库)STL从广义上分为:①容器(container) ②算法(algorithm) ③迭代器(iterator)容器和算法之间通过迭代器连接STL几乎所有的代码都采用了模板类或者模板函数 1.2 STL六大组件
STL大体分为六种:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器。
1、容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据
2、算法:各种常用的算法,如sort、find、copy等
3、迭代器:容器和算法之间连接器
4、仿函数:行为类似函数,作为算法的某种策略
5、适配器:用来修饰容器或者仿函数或迭代器接口
6、空间配置器:负责空间的配置与管理
容器:放置数据
STL容器就是运用最广泛的一些数据结构实现
常用的数据结构:数组、链表、树、队列、集合、映射表
这些容器分为序列式容器和关联式容器两种:
序列式容器:强调值的顺序,每个元素都有固定的位置
关联式容器:二叉树结构,没有严格上的物理上的顺序关系
算法:有限的步骤解决逻辑/数学问题
算法分为:质变算法,非质变算法
质变:会更改元素内容的算法、删除拷贝
非质变:运算不会改变元素内容,计数 查找
迭代器:算法要通过迭代器才能访问容器中的数据
每个容器都有自己的迭代器
用法类似于指针
在了解STL容器算法迭代器概念后,利用代码来加深理解
下面用最常用的容器:Vector,可以理解为数组来演示
容器:vector
算法:for_each
迭代器:vector< int>::iterator
#include
(*it)到最后是什么类型,可以直接看迭代器尖括号里面的东西即可就像下面的函数1,(*it)是Person类型函数2,(*it)是Person * 类型
#include
学习目标:容器中嵌套容器,将所有数据遍历输出
例:
#include
2、STL常用容器 2.1 string容器 2.1.1 string基本概念
本质:
- string是C++风格的字符串,而string本质上是一个类
string和char *的区别:- char *是一个指针 - string是一个类,类内部封装了char*,是char*型的容器
特点:
- string类内部封装了许多成员方法(例如:find,copy,delete) - string管理char*所分配的空间,不用担心下标越界
2.1.2 string构造函数构造函数原型:
- string();//创建空的字符串 - string(const char* s);//使用字符串s初始化 - string(const string& str);//使用字符串对象来初始化另一个string对象 - string(int n,char c);//使用n个字符c初始化
#include
功能描述:
- 给string字符串赋值(= 或者assign)
赋值操作原型函数
赋值操作一共有两种:一种是直接用等号=,原型如下 - string& operator=(const char* s);//char* 类型字符串,赋值给当前字符串 - string& operator=(const string &s);//把字符串赋值给当前的字符串 - string& operator=(char c);//字符赋值给当前的字符串另一种是assign() - string& assign(const char *s); //把字符串s赋给当前的字符串 - string& assign(const char *s, int n); //把字符串s的前n个字符赋给当前的字符串 - string& assign(const string &s); //把字符串s赋给当前字符串 - string& assign(int n, char c); //用n个字符c赋给当前字符
#include
总结:
string赋值方式很多,但是用 operator= 号是较为实用的方法
功能描述:
- 实现在字符串的末尾拼接字符串
函数原型:
- string& operator+=(const char* str); //重载+=操作符 - string& operator+=(const char c); //重载+=操作符 - string& operator+=(const string& str); //重载+=操作符 - string& append(const char *s); //把字符串s连接到当前字符串结尾 - string& append(const char *s, int n); //把字符串s的前n个字符连接到当前字符串结尾 - string& append(const string &s); //同operator+=(const string& str) - string& append(const string &s, int pos, int n);//字符串s中从pos开始的n个字符连接到字符串结尾
string str1 = "I";string str2 = "you,li ming";string str3 = "Life";str1 += "love";//追加字符串str1 += " ";//追加单个字符str1 += str2;//拼接字符串对象cout<
总结:
如果使用append(const string &s, int pos, int n)函数,应当弄明白字符的位置是从0开始的
2.1.5 string查找与替换功能描述:
查找:查找指定字符串是否存在替换:在指定的位置替换字符串
函数原型:
- int find(const string &str,int pos=0) const; 从pos位置开始查找str第一次出现的位置 - int find(const char *s,int pos=0) const;从pos位置开始查找s第一次出现位置 - int find(const char *s,int pos=0,int n) const; 从pos位置查找s的前n个字符第一次位置 - int find(const char c,int pos=0) const; 从pos位置查找字符c的第一次出现位置 - int rfind(const string &str,int pos=npos) const; 从pos开始查找str最后一次位置, - int rfind(const char *s,int pos=npos) const; 从pos开始查找s最后一次出现位置, - int rfind(const char *s,int pos,int n) const; 从pos查找s的前n个字符最后一次位置 - int rfind(const char c,int pos=0) const;查找字符c最后一次出现位置 - string &replace(int pos,int n,const string &str);替换从pos开始的n个字符为str - string &replace(int pos,int n,const char *s);替换从pos开始的n个字符为字符串srfind和find的区别:find默认从左往右查找,而rfind则代表从右往左查;find找到字符串后返回查找到的字符串的第一个字符的下标,找不到则返回-1;replace替换时要指定从哪儿个位置开始起,其后有多少个字符,替换成什么样的字符串。
tips:C++在函数声明时,后面跟个const是限定函数类型为常成员函数, 常成员函数是指不能改变成员变量值的函数。例如“double d() const;”,其中的其中的“const”限定了d()函数中不能有任何改变其所属对象成员变量值的功能,如果有则会在编译阶段就报错。它的主要作用就是能使成员函数的意义更加清楚,我们可在不改变对象的成员函数的函数原型中加上const说明。在需要增加可读性和减少逻辑出错的情况下,就可以用这种形式。
void test01(){string str1 = "zainashandenaoyouyiqunljl";int pos = str1.find("i");if (pos == -1)cout << "未找到" << endl;elsecout << pos << endl;pos = str1.rfind("i");cout<
比较方式:
比较字符的ASCII码值= return 0> return 1< return -1
函数原型:
在string类内部有这两个操作:int compare(const string &s) const; //与string对象字符串s比较int compare(const char *s) const; //与字符串s比较
string str1 = "hello!";string str2 = "hillo!";if (str1.compare(str2) == 0){cout << "str1和str2相同!" << endl;}else if(str1.compare(str2) ==-1){cout << "str1小于str2!" << endl;}elsecout<<"str1大于str2"<
总结:
一般用来比较字符串是否相等
2.1.7 string字符存取string中单个字符存取的方式有两种
在string类内部有这两个操作: char& operator[](int n); //通过[]方式取字符 char& at(int n); //通过string类内部at方法获取字符
string str = "hello world";cout<
函数原型:
在string类内部有这两个操作:string& insert(int pos, const char* s);//通过指向字符常量区域的指针对调用该成员函数的对象来插入字符string &insert(int pos,const string &str); //通过string类型的对象插入字符string &insert(int pos,int n,char c); //在指定位置插入n个字符cstring &erase(int pos,int n=npos); //删除从pos开始的n个字符
str.insert(1,"ag")
总结
通常情况下直接str.insert(1,"ag")就行;
2.1.8 string子串获取函数原型:
string substr(int pos = 0;int n=npos) const;
void test02(){string str;cin >> str;string userName = str.substr(0,str.find("@"));cout<
2.2 vector容器 2.2.1 vector基本概念
功能:
vector数据结构和数组非常相似,也称为单端数组
vector与普通数组区别:
不同之处在于数组是静态空间,而vector可以动态扩展
动态扩展:
①并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间。
②vector容器的迭代器是支持随机访问的迭代器
函数原型:
vector
vector
函数原型:
vector &operator = (const vector &vec); //重载等号操作符assign(begin,end);//将[ begin, end ]区间的数据拷贝赋值给本身assign(n,elem); //将n个elem拷贝赋值给本身
示例:
vector
函数原型:
empty(); //判断容器是否为空capacity(); //容器的容量size(); //返回容器中元素的个数resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除。resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除总结: - 判断是否为空--- empty() - 返回元素个数--- size() - 返回容量个数--- capacity() - 重新指定大小--- resize()
示例:
#include
函数原型:
push_back(ele) //尾部插入元素pop_back() //删除尾部元素insert(const_iterator pos,ele) //迭代器指向位置pos插入eleinsert(const_iterator pos,int count,ele) //迭代器指向pos插入count个元素eleerase(const_iterator start,const_iterator end) //删除迭代器从start到end之间的元素clear() //删除容器中所有元素
总结: 插入有尾部插入、通过迭代器插入某个元素、通过迭代器插入区间的元素; 删除有尾部删除,通过迭代器删除某个元素、通过迭代器删除区间的元素; 清空元素。示例:
v.push_back(12);v.pop_back();v.insert(v.begin(),100);v.insert(v.begin(),2,1000);v.erase(v.begin());v.erase(v.begin(),v.begin()++);v.clear();
2.2.6 vector容器数据存取函数原型:
at(int idx); //返回索引idx所指的数据operator[]; //返回索引idx所指的数据front(); //返回容器中第一个数据元素back(); //返回容器中最后一个数据元素
示例:
for(int i = 0;i < v.size();i++){cout << v[i] << endl;cout << v.at(i) <
函数原型:
swap(vec): //将vec与本身的元素互换
示例:
v1.swap(v2);
妙用:
有一说一,这个里面的那个利用匿名对象来收缩空间的方法胎牛皮了!!!!!!#include
功能描述:
减少vector在动态扩展容量时的扩展次数
函数原型:
reserve(int len); 容器预留len个元素长度,预留位置不初始化,元素不可访问
示例:
v.reserve(100000);
2.3 deque容器 2.3.1 deque容器基本概念
特性:
双端数组,可以对头端进行插入删除操作
deque容器的迭代器也是支持随机访问的
使用的时候需要包含头文件:#include与vector区别:
vector对于头部的插入删除效率低,数据量越大,效率越低deque相对而言,对头部的插入删除速度回比vector快vector访问元素时的速度会比deque快,这和两者内部实现有关
deque内部工作原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
函数原型:
deque
示例1:
deque
迭代器:
当仅仅是为了遍历,而不需修改时候,应当加上const关键字
const类型的容器需要const_iterator 迭代器才不会报错
示例2:
void printDeque(const deque
2.3.3 deque赋值操作
函数原型:
deque& operator=(const deque &deq); 重载等号操作符assign(beg,end); 将[beg,end)区间中的数据拷贝赋值给本身assign(n,elem); 将n个elem拷贝赋值给本身
示例:
deque
需要注意的点:
deque容器是没有容量这个概念的,所以不像vector中有capacity函数
函数原型:
deque.empty(); 判断容器是否为空deque.size(); 返回容器中元素的个数deque.resize(num); 重新指定容器的长度为num,若容器变长,则默认值填充新位置, 若容器变短,则末尾值超出容器长度的元素被删除deque.resize(num,elem); 重新指定容器的长度为num,若容器边长,则以elem值填充新位置, 如果容器变短,则末尾超出容器长度的元素被删除
总结:
判断是否为空 --- empty返回元素个数 --- size重新指定个数 --- resize
2.3.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,beg,end); 在pos位置插入[beg,end)区间的数据,无返回值clear(); 清空容器的所有数据erase(beg,end); 删除[beg,end)区间的数据,返回下一个数据的位置erase(pos); 删除pos位置的数据,返回下一个数据的位置
示例:
d.push_back(10);d.pop_front();
2.3.6 deque数据存取
函数原型:
at(int idx); 返回索引idx所指的数据operator[]; 返回索引idx所指的数据front(); 返回容器中第一个数据back(); 返回容器中最后一个数据
示例:
for(i=0; i
2.3.7 deque排序
注意:
注意包含头文件;sort算法默认升序;对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序;
算法:
sort(iterator beg, iterator end);
示例:
sort(d1.begin(), d1.end());
2.4 stack容器 2.4.1 stack基本概念
2.4.2 stack常用接口概念: stack是一种先进后出(first in first out)的数据结构,
它只有一个出口;
栈中只有栈顶的元素才能被访问到。
stack不提供遍历功能,也不提供迭代器。
入栈-push
出栈-pop
函数原型:
stack构造函数stack
示例:
s.top();//查看栈顶元素s.pop();//出栈
2.5 queque容器 2.5.1 queque基本概念
概念:
2.5.2 queque常用接口Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口
队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头 front()和队尾 back()才可以被外界使用,因此队列不允许有遍历行为
队列中进数据称为 — 入队 push
队列中出数据称为 — 出队 pop
构造函数:queue
总结:
2.5.3 queque示例入队:push
出队:pop
返回队头元素
返回队尾元素:back
判断队是否为空:empty
返回队列大小:size
#include
2.6 list 2.6.1 list基本概念
2.6.2 list构造函数优缺点:
优点:
可以对任意位置快速插入或者删除元素;
缺点:
容器的遍历速度,没有数组快;
占用空间比数组大;STL中的链表
STL中的链表是一个双向循环链表,迭代器只支持前移和后移,属于双向迭代器
总结:在STL中list和vector属于两个被最常使用的容器,各有优缺点。
函数原型
list
示例:
list
函数原型:
assign(begin, end); //将[beg, end)区间中的数据拷贝赋值给本身.assign(n, elem);//将n个elem拷贝赋值给本身list& operator=(const list &lst); //重载等号操作符swap(lst); //将lst与本身的元素互换。
例
list
函数原型
size(); //返回容器中元素的个数
empty(); //判断容器是否为空
resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
#include
函数原型:
* push_back(elem);//在容器尾部加入一个元素* pop_back();//删除容器中最后一个元素* push_front(elem);//在容器开头插入一个元素* 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位置的数据,返回下一个数据的位置。* remove(elem);//删除容器中所有与elem值匹配的元素。
2.7.6 list 数据存取函数原型:
l.front();返回容器第一个元素
l.back();返回容器最后一个元素
注意:不能用[]访问list容器中的元素
不能用at()方式访问list容器的元素
原因是:list本质链表,不适用连续线性空间存储数据,迭代器不支持随机访问(it = it+1错误),支持双向访问(it–)
l1.front();l2.back();
2.7.7 list 反转和排序函数原型:
reverse();翻转链表
sort()排序(成员函数, 默认升序, 可用仿函数来实现降序操作)
重要提示:
所有不支持随机访问迭代器的容器,不可以用标准算法
不支持随机访问迭代器的容器,内部会提供一些算法
list自带的排序算法默认是从小到大升序,如果要从大到小,利用回调函数或仿函数实现降序(此处为回调函数)
#include
#include
2.8 set/multiset容器 2.8.1 set基本概念对于自定义数据类型,必须指定排序规则,否则不知道如何进行排序
高级排序只是在排序规则上再进行一次逻辑规则的指定,并不复杂
2.8.2 set构造和赋值简介:所有元素都会在插入的时候自动排序
本质:set/multiset属于关联式容器,底层结构是用二叉树实现.
区别:set中不允许有重复的元素, multiset中允许有重复的元素
构造函数:
set< T> st; //默认构造函数:
set(const set &st); //拷贝构造函数赋值:
set& operator=(const set &st); //重载等号操作符
插入数据:
insert();
set
2.8.4 set容器插入和删除函数原型:
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
函数原型:
insert(elem); //在容器中插入元素。
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem); //删除容器中值为elem的元素。
s1.erase(s1.begin());s1.erase(30);
2.8.5 set查找和统计函数原型:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key); //统计key的元素个数,对于set来说只有0或1; 对于multiset能够大于1;
set
区别:
2.8.7 pair对组的创建set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
功能简介:
成对出现的数据,利用对组可以返回两个数据,其中第一个数据是first,第二个数据是second;
函数原型:
pair
p ( value1, value2 );
pairp = make_pair( value1, value2 );
示例:
//test func of pairvoid test4() { pair
set容器默认排序规则是从小到大,利用仿函数可以改变排序规则
不能在放入数据之后才指定排序方式, 应当在创建的时候指定排序方式
示例:创建了一个MyCompare类,重载函数调用运算符,并且在创建set容器时用类名作为第二个参数。
class myCompare{public:bool operator()(int v1, int v2){return v1 > v2;}};set
C++STL之map容器:发现的一篇挺好的文章
(1) map基本概念(2) map常用函数简介:
map中的所有元素都是pair
pair中第一个元素为key(键值)起到索引作用,第二个元素为value(值)
所有的元素都会根据元素的键值自动排序本质:
map/multimap属于关联式容器,底层结构是用二叉树实现
优点:
可以根据key值快速找到value值
map和multi的区别:
map不允许容器中有重复key值元素
multimap允许容器中有重复key值得元素其他
对于自定义数据类型, map必须指定排序规则,和set容器相同;
构造函数
map
赋值和交换
map& operator=(const map &mp);//重载等号操作符swap(mp);//交换两个集合容器
map大小操作
size();//返回容器中元素的数目empty();//判断容器是否为空
map插入操作
为什么不建议用第四种方式?
假如用第四种方式查找一个不存在的key,会自动新建一个键值对,值为零;因此用此种方式输出的时候应当确定此键值对已经存在了
map.insert(...); //往容器插入元素,返回pair
//1 map的四种插入方法void MapInsert(map
删除
clear();//删除所有元素erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。erase(keyElem);//删除容器中key为keyElem的对组。
查找统计
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器; //若不存在,返回map.end();count(keyElem); 返回容器中key为keyElem的对组个数。 对map来说,要么是0,要么是1。 对multimap来说,值可能大于1。lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
排序
map容器默认是升序排列, 利用仿函数来改变map容器的排序方式
class myCompare{public:bool operator()(int v1, int v2){//降序:return v1 > v2;//升序//return v1 < v2;}};map