一、常见的STL容器介绍
1、vector
(1)常用操作:赋值、删除、访问元素、获取元素个数
1)顺序赋值:
使用v.push_back(value),也可以使用v[i]=value赋值,但要注意数据越界问题;
2)删除(注意:删除后依然保持顺序连通性,并不是被删下标处变为空):
①删除任意指定位置:v.erase(iter)(注:返回值所指数据为原数列的下一个数值),遍历时删除元素要注意迭代器失效问题;
在遍历中使用erase()举例:
for(vector<int>::iterator iter=v.begin();iter!=v.end();)
{
if(*iter==5)
{
iter=v.erase(iter); //删除后该迭代器及其后面迭代器都已失效,必须重新赋值
}
else
{
cout<<*iter<<' ';
iter++;
}
}
注:vector<int>::iterator iter迭代器定义方式表明,迭代器前要有容器类型修饰符,以表明属于哪个容器的迭代器;
②删除末尾数值:v.pop_back();
3)访问
如101节所示,可以使用v[i]直接访问,只要自己注意访问越界就可;也可以使用v.at(i),该方式下编译器会自动检查越界;
4)获取元素个数
v.size(); //对各容器通用
(2)vector的其他作用
1)模拟循环链表
方法:使用迭代器实现,例如:
if(iter==v.end())
iter=v.begin();
2、stack
(1)常用操作:定义、出栈入栈、读取栈顶元素、获取元素个数、判断栈是否为空
1)定义:
stack<int> s 类似;
2)入栈出栈:
s.push(x)、s.pop();
注意:pop仅仅是出栈,不会返回值
3)读取栈顶数据
s.top();//返回值为栈顶数据
4)读取栈中实际数据个数
s.size();
5)判断栈是否为空
s.empty();
3、queue
(1)常用操作:定义、入队出队、访问队首队尾、获取队列中元素个数、判断对内是否为空
1)定义
queue<int> q 类似定义;
2)入队出队
q.push(x); //队首入队
q.pop(); //队尾出队,仅仅是出队,无返回值
3)访问队首队尾
q.front(); //访问队首元素
q.back(); //访问队尾元素
4)获取队列中元素个数
q.size();
5)判断队列是否为空
q.empty();
4、string
(1)定义并初始化、string对象操作(判断空、获取字符个数(不包括'\0')、字符串连接、字符串比较)
1)string对象的定义和初始化以及读写
string s1; 默认构造函数,s1为空串
string s2(s1); 将s2初始化为s1的一个副本
string s3("valuee"); 将s3初始化一个字符串面值副本
string s4(n,'c'); 将s4 初始化为字符'c'的n个副本
cin>>s5; 读取有效字符到遇到空格结束
getline(cin,s6); 读取一行字符串,空格可读入,直到‘\n’结束(换行结束),
getline(cin,s7,'a'); 一个直到‘a’结束,其中任何字符(包括'\n')都能够读入
2)string对象操作
①判断是否为空:
s.empty() 判断是否为空,bool型
②获取字符串中字符个数:
s.size() 或 s.length() 返回字符的个数(注意:不包括结尾'\0')
③字符串连接:
直接用加法,如s1+s2 连接,看下面例子:
可用此方法给字符串后面添加字符如:s=s+'a';
a: string s2=s1+", "; //对,把一个string对象和一个字符面值连接起来是允许的
b: string s4="hello "+", "; //错,不能将两个字符串面值相加(两个字符串都是常量,而相加结果应该先赋值给前者,前者不可修改,再赋给等号左边的,故该用法非法)
c: string s5=s1+", "+"world"; //对,前面两个相加相当于一个string对象;
d: string s6="hello" + ", " + s2; //错(原因同s4,第一个不能是常量)
(注:字符串尾部追加还可用s.append("abc")函数添加)
④字符串比较:
直接用算术比较符号(=、>=、<=、>、<、!=),例如:
s1==s2 相等,还用、有!=,<,<=,>,>= 字符串比较,返回true或false;
两个字符串短的与长的前面匹配,短的小于长的;
(2)string对象常用函数
1)插入函数:
包括迭代器操作和下标操作,下标操作更灵活;
s.insert( it , p );把字符串p插入到it的位置
s.insert(p,n,t);迭代器p元素之前插入n个t的副本
s.insert(p,b,e);迭代器p元素之前插入迭代器b到e之间的所有元素
s.insert(p,s2,poe2,len);在下标p之前插入s2下标从poe2开始长度为len的元素
s.insert(pos,cp,len);下标pos之前插入cp数组的前len个元素。
2)替换函数
s.assign(b,e);用迭代器b到e范围内的元素替换s
s.assign(n,t);用n个t的副本替换s
a.assign(s1,pos2,len);从s1的下标pos2开始连续替换len个。
s.replace ( 3 , 3 , " good " ) ;从第三个起连续三个替换为good
3)截取函数
s.substr(i,len); 截取s串中从i开始截取长度为len的子串
s.substr(i);截取从第i个元素开始到最后一个元素的子串
3)删除函数
s.erase( 3 )||s.erase ( 0 , 4 ) ; 删除第四个元素或第一到第五个元素
4)其他函数
s.find ( " cat " ) ;正向查找第一个出现的字符串”cat“,返回cat首字符下标值,查不到返回string::npos或者 -1(string::npos==-1);
——举例:string str="123good5good78\0";st=str.find("good"); 结果:st=3;
注意,此函数也可查找字符;
s.rfind ( " cat " ) ; 反向查找第一个出现的字符串”cat“,返回cat首字符下标值,查不到返回string::npos或者 -1(string::npos==-1);
——举例:string str="123good5good78\0";st=str.rfind("good"); 结果:st=8;
注意,此函数也可查找字符;
s.find_first_of(str); 函数是正向查找s中查找与str字符串中任何一个字符匹配的字符,如有,则返回第一个找到的字符下标,否则返回string::npos;
例如:string str="12345678\0";st=str.find_first_of("458god"); 结果:st=3;
s.find_last_of(str);函数是正向查找s中查找与str字符串中任何一个字符匹配的字符,如有,则返回最后一个找到的字符索引,否则返回string::npos;
例如:string str="12345678\0";st=str.find_last_of("458god"); 结果:st=7;
此外,find_last_of()的参数还可以是字符,例如filePath.find_last_of('\\')可以用来获取路径最后的文件名的首字符下标(注意必须使用'\\',因为一个反斜杠被认为是转义字符标志);
s.find_first_not_of(str);在字符串s中查找第一个与str中的任一字符都不匹配的字符,返回它的下标位置。搜索从index正向开始。如果没找到就返回string::nops;
find_last_not_of(str);在字符串s中查找最后一个与str中的任一字符都不匹配的字符,返回它的位置。搜索从index逆向开始。如果没找到就返回string::nops
s.append(args);将args接到s的后面;
s.compare ( " good " ) ;s与”good“比较相等返回0,比"good"大返回1,小则返回-1;
5)自己实现字符串和数值互相转化
①流对象:
//c++方法:将数值转换为string
string convert_to_string(double x)
{
ostringstream o;
if(o << x)
return o.str();
}
//c++方法,将string转化为数值
double convert_from_string(const string &s)
{
istringstream i(s);
double x;
if(i >> x)
return x;
return 0.0;
}
②使用C++库函数实现(需要引入<string>):
——数值转化为string:
string str=std::to_string(num);
注意,上述在VS2010中会出错,因为vs2010只实现了部分类型,对于int 、bool等类型需要如下:
std::to_string(static_cast<long long>(3));
std::to_string(static_cast<long long>(true));
——string转化为数值
int num=std::stoi(const string& str, size_t* idx = 0, int base = 10);//结果是十进制
除int外,还有stol、stof、stod等;
形参说明:
str:表示被转换的字符串;
idx:表示一个size_t*的指针类型,默认为空值或0;
base:表示转换基准,即表示将当前字符串进制,默认是10进制。
举例:
string testStr="12345";
int nn=std::stoi(testStr,0,8);
cout<<nn<<endl;
结果是:5349(十进制)
二、迭代器介绍
1、迭代器的定义:
定义vector<int>容器的迭代器:vector<int>::iterator iter;
定义map<string, pair<string,int>>容器的迭代器:map<string, pair<string,int>>::iterator iter;
……
2、迭代器在遍历中的使用
①遍历中不删除或插入元素:for(vector<int>::iterator iter=v.begin();iter!=v.end();iter++){ }
②遍历中需要删除或插入元素,如下:
for(vector<int>::iterator iter=v.begin();iter!=v.end();)
{
if(*iter==5)
{
iter=v.erase(iter); //删除后该迭代器及其后面迭代器都已失效,必须重新赋值
}
else
{
cout<<*iter<<' ';
iter++;
}
}
注:vector<int>::iterator iter迭代器定义方式表明,迭代器前要有容器类型修饰符,以表明属于哪个容器的迭代器;
三、常用STL算法介绍
说明:
(1)STL几乎封装了容器常用的一切算法,平时多使用可以减少代码量,节省时间,是否减少复杂度根据情况而定;
(2)使用前需要引入<algorithm>;
1、排序算法sort()和stable_sort()
(1)使用sort()或者stable_sort(),这两个函数是属于algorithm库的,对各个有序容器(不包括map这种无序的)通用;①sort(v.begin(),v.end());//不稳定排序,默认升序排列
②stable_sort(v.begin(),v.end());//稳定排序,默认升序
(2)若要降序排列还需要增加一个比较函数,例如对于容器vector<pair<string,int>> v容器排序,比较函数如下:
bool cmp(const pair<string, int> &a, const pair<string, int> &b) //参数类型为容器中元素类型的常量引用形式
{
return a.second>b.second;
}
然后,调用sort()或者stable_sort()函数如下:
sort(v.begin(),v.end(),cmp); //表示按照v中pair类型元素的第二个值的降序排序
2、判断容器中是否有某元素算法find()
(1)使用find()函数可以查找一个容器中是否有某元素,有就返回迭代器地址,无则返回xx.end();
例如:vector<int> v;
find(v.begin(),v.end(),10); //查找v中是否有值为10的元素
应用举例:
vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
vector<int>::iterator ret;
ret = std::find(vec.begin(), vec.end(), 15);
if(ret == vec.end())
cout << "not find" << endl;
else
cout << "finded" << endl;
3、容器元素顺序反转函数
reverse(begin(),end())可以对vector、string进行元素顺序反转:
(1)string反转
string s;
reverse ( s.begin(), s.end () );//对string反向排序;
(2)vector反转
vector<int> v;
reverse ( v.begin(), v.end () );//对vector反向排序;