二、STL
3. 常用容器
3.1 string容器
3.1.1 string基本概念
- 本质
- string是C++风格字符串,本质上是个类
- string与char *的区别
- char*是个指针
- string是一个类,类内部封装了char*,管理这个字符串,是个char*型的容器
- 特定
- 内部封装了很多成员方法
find
、copy
、delete
、insert
、replace
- string管理char*分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
- 内部封装了很多成员方法
- 自得
使用string函数时,总有三种重载的传入方式
3.1.2 string构造函数
灵活使用
//string(); 创建空字符串
string s1;
//string(const char* s);使用字符串s初始化
const char* str="s2";
string s2(str);
//string(const string& str);有另一string对象初始化
string s3(s2);
//string(int n, char c):使用n个字符c初始化
string s4(5,'a');
3.1.2 string赋值操作
- 利用=
函数原型:string& operator=()//(const char* s) char*类型字符串赋给当前字符串 string s1; s1 ="hello"; //(const string &s) 一字符串赋给当前字符串 string s2; s2=s1; //(const char c) 字符赋给当前字符串 string s3; s3='a';
- 利用assign函数
函数原型:string& assign()//(const char* s) char*类型字符串赋给当前字符串 string s1; s1.assign("hello"); //(const char* s,int n) char*类型字符串前n个字符赋给当前字符串 string s2; s2.assign("hello",3); //(string &s) 一字符串赋给当前字符串 string s3; s3.assign(s2); //(int n, char c) 使用n个字符c赋给当前字符串 string s4; s4.assign(5,'a');
3.1.3 string字符串拼接
实现在字符串末尾拼接字符串
- 利用+=
函数原型:string& operator=+()//(const char* s) string s1="hello "; s1+="world"; //(const char c) s1+="!"; //(const string &s) string s2="thanks"; s1+=s2;
- 利用append()函数
函数原型:string& append()//(const char* s) string s1="hello "; s1.append("world"); //(const char* s,int n) s1.append("world hhh",5); //(const string &s) string s2="thanks you"; s1.append(s2); //(const string &s,int pos,int n) //第二个参数为从哪个位置开始截取,,第三个参数表示截取几个字符 string s2="thanks you"; s1.append(s2,0,5);
3.1.4 string查找和替换
查找:查找指定字符串是否存在。
- 利用find函数与rfind函数
- find从左往右查找(第一次出现),rfind从右往左查找(最后一次出现)
- 找到后返回第一个字符所在的位置,没找到返回-1。
//int find(const string &s,int pos),pos默认为0, string str="abcdefg"; int ret=str.find("fg"); //int find(const string &s,int pos,int n) pos位置查找s的前n个字符 //int rfind(const string &s,int pos),pos默认为end string str="abcdefgab"; int ret=str.rfind("ab");
替换:在指定的位置替换字符
- 利用replace()函数
- 指定从哪个位置起,多少个字符,替换成怎么样的字符
//string& replace(int pos,int n,const string &s) 从pos开始n个字符 string str="abcdefg"; str.replace(2,3,"111");//ab111fg
3.1.5 string字符串的比较
- compare()函数
- 主要是为了判断相等,不是谁大谁小
- 按字符的ASCII码值进行对比
- =返回0,>返回1,<返回-1
//int compare(const string &s) string str1="cd"; string str2="ab"; int ret=str1.compare(str2);
3.1.6 string字符存取
- 通过[]访问单个字符
str[i] - 通过at()函数
str.at(i)
3.1.7 string子串
- substr()函数
- 实用性强,比如从邮箱中找出函数名
//string substr(int pos,int n) 返回pos开始的n个字符 string str1="abcdefg"; string str2= str1.substr(1,3);//bcd
3.1.8 string插入和删除
- insert()函数(插入)
//string& insert(int pos,const string &s) string str1="cd"; str1.insert(1,"11");//c11d
- erase()函数(删除)
//string& erase(int pos,int n) 删除从Pos开始的n个字符 string str1="abcdefg"; str1.erase(2,3);//abfg
3.2 vector容器
3.2.1 vector基本概念
- 功能
与数组相似,只能在尾端进行操作,一块连续的内存空间称为单端数组 - 与普通数组区别
数组是静态的,vector可以动态扩展
动态扩展:不是在原空间之后续新空间,而是找更大的内存空间,将原数据拷贝到新空间,再释放原空间 - vector的迭代器是支持随机访问迭代器,常用的迭代器有:
v.begin():指向第一个数据,v.end():指向最后一个数据的后一个位置
v.rend():指向第一个数据的前一个位置,v.rbegin():指向最后一个数据
3.2.2 vector构造函数
四种构造方式
//vector<T> v; 默认构造
vector<int>v1;
//vector(v.begin(),v.end()) 通过区间方式(前闭后开)进行构造
vector<int>v2(v1.begin(),v1.end());
//vector(n,elem) n个elem方式构造
vector<int>v3(10,100);
//vector<const vector &vec> 拷贝构造
vector<int>v4(v3);
3.2.3 vector赋值操作
三种赋值操作
//operator=
vector<int> v1;
vector<int> v2;
v2=v1;
//assign(v.begin(),v.end())
vector<int> v3;
v3.assign(v1.begin(),v1.end());
//assign(n,elem)
vector<int> v4;
v4.assign(10,100);
3.2.4 vector容量和大小
empty()
:判空(返回真为空)
capacity()
:返回容器的容量(≥size)
size()
:返回容器中元素的个数
resize(int num,elem)
:重新指定容器长度为num,若变长,以elem(不写的话默认为0)填充新位置,若变短,末尾超出部分删除
3.2.5 vector插入和删除
- 插入
push_back(elem)
:尾部插入元素elem
insert(const_iterator pos,elem)
:迭代器指向的位置pos插入元素elem
insert(const_iterator pos,int count,elem)
:迭代器指向位置pos插入count个元素elem - 删除
pop_back()
:删除最后一个元素
erase(const_iterator pos)
:删除迭代器指向的元素
erase(const_iterator start,const_iterator end)
:删除迭代器从start到end之间的元素
clear()
:删除容器中的所有元素
3.2.6 vector数据存取
at(int idx)
:返回索引idx所指的数据
[idx]
:返回索引idx所指的数据
front()
:返回容器中第一个元素
back()
:返回容器中最后一个元素
3.2.7 vector互换容器
swap(vector)
:将vector与本身的元素互换
实现收缩内存的效果
//已知v.capacity()=10000;
vector<int>(v).swap(v);
//通过拷贝构造了一个匿名对象,再与v本身进行交换,成功将收缩内存
3.2.8 vector容器预留空间
减少vector再动态扩展容量时的扩展次数
reserve(int len)
:容器预留len个元素长度,预留位置不初始化,元素不可访问
3.3 deque容器
3.3.1 deque容器的基本概念
- 功能
可以对头、尾端进行操作,称为双端数组 - deque与vector的区别
- vector访问速度比deque快
- deque头部插入删除速度比vector快
- 内部工作原理
内部有中控器,维护每段缓冲区的内容,维护的是每个缓冲区的地址,缓冲区中存放真实的数据,使得使用deque时像一片连续的内存空间 - vector的迭代器是支持随机访问迭代器,常用的迭代器有:
v.begin():指向第一个数据,v.end():指向最后一个数据的后一个位置
3.3.2 deque的构造函数
四种构造函数(与vector相同)
//deque<T> v; 默认构造
deque<int>v1;
//deque(v.begin(),v.end()) 通过区间方式(前闭后开)进行构造
deque<int>v2(v1.begin(),v1.end());
//deque(n,elem) n个elem方式构造
deque<int>v3(10,100);
//deque<const deque &vec> 拷贝构造
deque<int>v4(v3);
3.3.3 deque赋值操作
三种赋值操作(与vector相同)
//operator=
deque<int> v1;
deque<int> v2;
v2=v1;
//assign(v.begin(),v.end())
deque<int> v3;
v3.assign(v1.begin(),v1.end());
//assign(n,elem)
deque<int> v4;
v4.assign(10,100);
3.3.4 deque大小操作
没有容量的概念
empty()
:判空(返回真为空)
size()
:返回容器中元素的个数
resize(int num,elem)
:重新指定容器长度为num,若变长,以elem(不写的话默认为0)填充新位置,若变短,末尾超出部分删除
3.3.5 deque插入和删除
- 两端操作
push_back(elem)
:尾部添加一数据
push_front(elem)
:头部插入一数据
pop_back(elem)
:尾部删除一元素
pop_front(elem)
:头部删除一元素 - 指定位置操作
insert(const_iterator pos,elem)
:迭代器指向的位置pos插入元素elem,返回新元素的位置
insert(const_iterator pos,int count,elem)
:迭代器指向位置pos插入count个元素elem,无返回值
insret(const_iterator pos,const_iterator start,const_iterator end)
在pos位置插入迭代器从start到end之间的元素,无返回值
erase(const_iterator pos)
:删除迭代器指向的元素,返回下一个数据的位置
erase(const_iterator start,const_iterator end)
:删除迭代器从start到end之间的元素,返回下一个数据的位置
clear()
:删除容器中的所有元素
3.3.6 deque存取操作
at(int idx)
:返回索引idx所指的数据
[idx]
:返回索引idx所指的数据
front()
:返回容器中第一个元素
back()
:返回容器中最后一个元素
3.4 stack容器
栈,先进后出,一个出口,只能操作栈顶元素,不允许遍历,
- 构造函数
stack<T> stk
:默认构造函数
stack(const stack &stk)
:拷贝构造 - 赋值操作
stack& operator=(const stack &stk)
:等号赋值 - 数据存取
push(elem)
:栈顶添加元素
pop()
:栈顶移除一个元素
top();
:返回栈顶元素 - 大小操作
empty()
:判断栈堆是否为空
size()
:返回栈的大小
3.5 queue容器
队列,先进先出,一端移除(出队,队头),一端新增(入队,队尾),只能操作队头队尾,不允许遍历。
- 构造函数
queue que
:默认构造函数
queue(const queue &que)
:拷贝构造 - 赋值操作
queue& operator=(const queue &que)
:等号赋值 - 数据存取
push(elem)
:队尾添加元素
pop()
:队头移除一个元素
back()
:返回最后一个元素
front()
:返回第一个元素 - 大小操作
empty()
:判断队列是否为空
size()
:返回队列的大小
3.6 list容器
3.6.1 基本概念
STL提供的是双向循环链表
list迭代器为双向迭代器,只支持前移和后移
动态存储分配,不会造成内存浪费和溢出
插入删除方便,遍历麻烦
插入和删除不会造成原有list迭代器的失效(vector中不成立)
list与vector最常用,各有优缺点,注意选择
3.6.2 list构造函数
四种构造函数(几种STL的构造方式都相同)
//list<T> lst; 默认构造
list<int>L1;
//list(lst.begin(),lst.end()) 通过区间方式(前闭后开)进行构造
list<int>L2(L1.begin(),L1.end());
//list(n,elem) n个elem方式构造
list<int>L3(10,100);
//list<const deque &lst> 拷贝构造
list<int>L4(L3);
3.6.3 list赋值和交换
assign(beg,end)
区间赋值
assign(n,elem)
n个elem赋值
list& operator=(const list &lst)
等号
swap(lst)
与lst本身的元素互换
3.6.4 list大小操作
empty()
:判空(返回真为空)
size()
:返回容器中元素的个数
resize(int num,elem)
:重新指定容器长度为num,若变长,以elem(不写的话默认为0)填充新位置,若变短,末尾超出部分删除
3.6.5 list插入和删除
- 两端操作
push_back(elem)
:尾部添加一数据
push_front(elem)
:头部插入一数据
pop_back(elem)
:尾部删除一元素
pop_front(elem)
:头部删除一元素 - 其他位置操作
insert(const_iterator pos,elem)
:迭代器指向的位置pos插入元素elem,返回新元素的位置
insert(const_iterator pos,int count,elem)
:迭代器指向位置pos插入count个元素elem,无返回值
insret(const_iterator pos,const_iterator start,const_iterator end)
在pos位置插入迭代器从start到end之间的元素,无返回值
erase(const_iterator pos)
:删除迭代器指向的元素,返回下一个数据的位置
erase(const_iterator start,const_iterator end)
:删除迭代器从start到end之间的元素,返回下一个数据的位置
clear()
:清空容器中的所有元素
remove(elem)
:移除容器中与elem相匹配的所有值
3.6.6 list数据存取
front()
:返回第一个元素
back()
:返回最后一个元素
不能使用[]或者at()访问,因为list不是连续线性的空间存储数据
3.6.7 list反转和排序
reverse()
:反转
sort()
:排序(默认为从小到大,若要更改可添加参数)
L.sort(myCompare);//降序排列
bool myCompare(int val1,int val2){
return val1>val2;
}
在所有不支持随机访问迭代器的容器中,不可以使用标准算法,它的内部会提供一些算法,使用时直接调用即可
3.7 set/multiset容器
3.7.1 set基本概念
- 功能
所有元素在插入时自动排序 - 本质
属于关联式容器,底层结构为二叉树 - 区别
- set不允许插入重复元素,但multiset允许
- set插入数据的同时会返回插入结果.表示是否插入成功(pair<Iterator,bool>)
- multiset不会检测数据。
3.7.2 set构造和赋值
- 构造
set<T> s
:默认构造
set(const set &st):
拷贝构造 - 赋值
set operator=(const set &st)
:等号赋值
3.7.3 set大小与交换
- 大小
size()
:返回容器中元素的个数
empty()
判空 - 交换
swap(st)
:交换两个容器
3.7.4 set插入与删除
- 插入
insert(elem)
:插入一个数 - 删除
erase(const_iterator pos)
:删除迭代器指向的元素,返回下一个数据的位置
erase(const_iterator start,const_iterator end)
:删除迭代器从start到end之间的元素,返回下一个数据的位置
erase(elem)
:删除容器中值为elem的元素
clear()
:清空容器中的所有元素
3.7.5 set查找与统计
- 查找
find(elem)
:若找到返回该元素迭代器位置,若没找到返回set.end() - 统计
count(elem)
:统计elem的元素个数
对于set而言,count=0或者=1
3.7.6 set容器排序
仿函数修改默认的排序大小
- set存放内置数据类型
class myCampare(){ public: bool operator()(int v1,int v2){ return v1>v2; } } //将自定义类型写在函数列表中 set<int,myCompare>s;//则此set容器为自定义类型排序
- set存放自定义数类型
对于自定义数据类型,必须指定排序规则class myCampare(){ public: bool operator()(const Person&v1,const Person&v2){ //按照年龄降序 return p1.age>p2.age; } } set<Person,myCompare>s;
3.8 map/multimap容器
3.8.1 pair队组
-
创建方式(二种)
//第一种方式 pair<string,int>p1("Tom",20); //第二种方式 pair<string,int>make_pair("Jerry",30);
-
调用
p.first
:调用第一个参数
p.second
:调用第二个人参数
3.8.2 map基本概念
- 简介
- map中所有元素都是pair
- pair中第一个元素为key(键值),索引作用,第二个元素为value(实值)
- 所有元素根据元素的键值自动排序
- map中所有元素都是pair
- 本质
属于关联式容器,底层结构为二叉树 - 优点
可以根据key值快速找到value值 - map/multimap区别
map中不允许有重复的key值元素,但multimap中允许
3.8.3 map构造和赋值
- 构造
map<T1,T2> mp
:默认构造
map(const map &mp)
:拷贝构造 - 赋值
map& operator=(const map &mp)
等号赋值
3.8.4 map大小与交换
- 大小
size()
:返回容器中元素的个数
empty()
判空 - 交换
swap(mp)
:交换两个容器
3.8.5 map插入和删除
- 插入(三种)
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;//[]可以利于key访问value
- 删除
erase(const_iterator pos)
:删除迭代器指向的元素,返回下一个数据的位置
erase(const_iterator start,const_iterator end)
:删除迭代器从start到end之间的元素,返回下一个数据的位置
erase(key)
:删除容器中值为key的元素
clear()
:清空容器中的所有元素
3.8.6 map查找和统计
- 查找
find(key)
:若找到返回该元素迭代器位置,若没找到返回map.end() - 统计
count(key)
:统计key的元素个数
对于map而言,count=0或者=1
3.8.7map排序
与set排序相同
4. 常用算法
4.1 常用遍历算法
4.1.1 for_each
for_each(v.begin,v.end,print01);
for_each(v.begin,v.end,print02());
//普通函数
void print01(int val){
cout<<val<<" ";
}
//仿函数
class print02{
public:
void operator()(int val){
cout<<val<<" ";
}
}
4.1.2 transform
搬运容器到另一个容器
transform(Iterator beg1,Iterator end1.Iterator beg2,_func);
//beg1:原容器开始迭代器
//end1:原容器结束迭代器
//beg2:目标容器开始迭代器
//__func:函数或者函数对象(对搬运的元素进行操作)
class Transform{
public:
int operator()(int val){
return val;//可以对元素进行操作
}
}
void test(){
vector<int> v1;
for(int i=0;i<10;i++){
v1.push_back(i);
}
vector<int>v2;
v2.resize(v1.size());//目标容器需要开辟空间
transform(v1.begin(),v1.end(),v2.begin(),Transform());
}
4.2 常用查找算法
4.2.1 find
查找指定元素,若找到返回该元素迭代器位置,若没找到返回结束迭代器end()
find(iterator beg,iterator end,values)
-
查找内置数据类型
vector<int>::iterator it=find(v1.begin(),v1.end(),5); if(it==v1.end()) cout<<"x"<<endl; else cout<<"√"<<endl;
-
查找自定义数据类型
//在Person中 bool operator==(const Person &p){ if(this->Name==p.Name&&this->Age==p.Age){ return true; } else{ return false; } } //在test中 Person pp("bbb",30); vector<int>::iterator it=find(v1.begin(),v1.end(),pp); if(it==v1.end()) cout<<"x"<<endl; else cout<<"√"<<endl;
4.2.2 find_if
按条件查找元素,返回迭代器
find_if(iterator beg,iterator end,_Pred)
//_Pred或者谓词
-
查找内置数据类型
class Myfind{ public: bool operator()(int val){ return val>5; } }; vector<int>::iterator it=find_if(v1.begin(),v1.end(),Myfind()); if(it==v1.end()) cout<<"x"<<endl; else cout<<"√"<<*it<<e
-
查找自定义数据类型
class Myfind{ public: bool operator()(int val){ return val>5; } };
4.2.3 adjacent_find
查找相邻重复元素,返回相邻元素的第一个位置的迭代器
adjacent_find(iterator beg,iterator end);
vector<int>::iterator it=adjacent_find(v1.begin(),v1.end());
if(it==v1.end())
cout<<"x"<<endl;
else
cout<<"√"<<*it<<endl;
4.2.4 binary_search
查找指定元素是否存在,找到返回true,没找到返回false
bool binary_search(iterator beg,iterator end,value)
必须为有序序列,在无序序列中不可用
bool ret=binary_search(v.begin(),v.end,5);
if(ret)
cout<<"x"<<endl;
else
cout<<"√"<<*it<<endl;
4.2.5 count
统计元素个数
count(iterator beg,iterator end,value)
-
统计内置数据类型
int num=count(v.begin(),v.end(),5); //5的元素的个数
-
统计自定义数据类型
//在Person中 bool operator==(const Person &p){ if(this->Name==p.Name){ return true; } else{ return false; } }
4.2.6 count_if
按条件统计元素个数
count(iterator beg,iterator end,_pred)
-
统计内置数据类型
class Myfind{ public: bool operator()(int val){ return val>5; } }; int num=count_if(v.begin(),v.end(),Myfind());
-
统计自定义数据类型
class Myfind{ public: bool operator()(const Person&p){ return p.age>20; } }; int num=count_if(v.begin(),v.end(),Myfind());
4.3 常用排序算法
4.3.1 sort
对容器内部元素进行排序
sort(iterator beg,iterator end,_pred)
//_Pred可以不写,默认为从大到小排序
//降序
sort(v.begin(),v,end(),greater<int>());
4.3.2 random_shuffle
洗牌,指定范围内的元素随机调整次序
random_shuffle(iterator beg,iterator end)
srand(unsigned int)time(NULL));
//为了打乱更真实
random_shuffle(v.degin,v.end);
4.3.3 merge
合并两个容器的元素,并存储到另一个容器中
两个容器必须是有序的,且排列顺序是一致的,存储之后也是有序的
merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)
//beg1、end1容器1开始、结束迭代器
//beg2、end2容器2开始、结束迭代器
//target目标容器开始迭代器
vector<int> v3;
v3.resize(v1.size()+v2.size());//目标容器需要提前开辟空间
merge(v1.begin(),v1.end,v2.begin(),v2,end(),v3.begin());
4.3.4 reverse
将元素内容器进行反转
reverse(iterator beg,iterator end)
4.4 常见拷贝和替换算法
4.4.1 copy
容器内指定元素拷贝到目标容器中
copy(iterator beg,iterator end,iterator target)
vector<int> v2;
v2.resize(v1.size());//提前给目标容器开辟空间
copy(v1.begin(),v1.end,v2.begin())
4.4.2 replace
容器内指定范围的旧元素更改为新元素
replace(iterator beg,iterator end,oldvalue,newvalue);
4.4.3 replace_if
将区间内满足条件的元素,替换成指定元素
replace_if(iterator beg,iterator end,_pred,value);
class Myfind{//利于仿函数筛选满足的条件
public:
bool operator()(int val){
return val>5;
}
};
replace_if(v.begin,v.end,Myfind,200);
4.4.4 swap
互换两个容器中的元素
两个容器需要是同种类型
swap(container c1,container c2)
4.5 常用算术生成算法
属于小型算法,头文件为#include<numeric>
4.5.1 accumulate
计算容器元素累计总和
accumulate(iterator beg,iterator end,value)
//value为起始累加值
int total=accumulate(v.begin,v.end,1000);
4.5.2 fill
向容器中填充指定的元素
full(iterator beg,iterator end,value)
4.6 常用集合算法
4.6.1 set_intersection
求两个容器的交集,返回值为交集最后一个元素的位置
两个集合必须是有序序列
set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)
vector<int> v3;
v3.resize(min(v1.size(),v2.size());//目标容器开辟空间需要从两个容器中取小值
vector<int>::iterator itEnd
=set_intersection(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
for_each(v3,begin(),itEnd,myprint());//遍历时要用返回的迭代器位置
4.6.2 set_union
求两个集合的并集,返回值为并集最后一个元素的位置
两个集合必须是有序序列
set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)
vector<int> v3;
v3.resize(v1.size()+v2.size());//目标容器开辟空间需要两个容器size相加
vector<int>::iterator itEnd
=set_union(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
for_each(v3,begin(),itEnd,myprint());//遍历时要用返回的迭代器位置
4.6.3 set_difference
求两个集合的差集,返回值为差集最后一个元素的位置
A-B与B-A的差集时不同的,注意区分前后(差集:除去相同部分)
两个集合必须是有序序列
set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)
vector<int> v3;
v3.resize(max(v1.size(),v2.size());//目标容器开辟空间需要从两个容器中取最大值
vector<int>::iterator itEnd
=set_union(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
for_each(v3,begin(),itEnd,myprint());//遍历时要用返回的迭代器位置