stl容器学习——queue,stack,list与string

时间:2023-03-08 17:47:15

简介:本文记录了对string list queue stack四个容器的学习总结,包含有四种容器常用的函数介绍和一些使用过程中碰到的细节总结,在list容器中介绍了迭代器的使用。

头文件

想要用哪一种容器,就要加上对应的头文件

比如想要使用queue , 就要加上 #include<queue>

以此类推,想要使用STL库中的容器,只要加上它们的头文件就好。


string

目录部分

1.string的定义及初始化

2.string的运算符和比较符使用

3.常用的一系列函数

1.string的定义及初始化

string str string可以看成一种定义的字符串类型,定义的方法和基本类型(int等)是一样的。

string str = "hello world"; string能够在定义的时候直接用"="进行赋值,这样str代表的就是"hello world"这一个字符串。

str = "hello world"; 当然在定义结束后再赋值也是可以的。

在这里要介绍一下assign这个函数,它是个用来对string赋值的函数。

assign的赋值是覆盖性的,会覆盖掉原来字符串的内容,相当于重置了一遍后再写入新的内容。

我们先定义两个字符串string str1,str2;

再定义一个字符串并初始化为"hello world": string str="hello world";

现在我们开始来介绍assign函数的几个常见用法

① 用一个字符串给另一个字符串赋值

str1.assign(str); 这里是将str的值赋给了str1,而str的值为"hello world",所以此时的str1也是"hello world";

那么如果我们给这个函数多加入两个参数呢?

str1.assign(str,int index,int size_count);

我们在函数后面多加了两个参数**index 和 size_count **

其中index代表着str这个字符串的下标,size_count代表着要被赋值的长度。

我们不妨令index=1,size_count=5,那么执行完str1.assign(str,1,5);

我们会得到这样的结果:str1="ello " (末尾有一个空格)

不难发现,这次的assign函数是从str字符串的下标1处开始,将往后的5个长度赋值给了str1,所以实际上str1就是str从 index下标 处开始,长度为 size_count 的一个字串。

那么如果只加入index参数,而不加入size_count这一个参数呢?

不妨再来执行下这个代码str1.assign(str,2);

此时的index=2,而str1="llo world";

很容易发现,如果不输入参数size_count,那么assign函数执行的就是将str字符串从index下标处开始的所有内容都赋给str1。

②用字符串常量对字符串进行赋值

用字符串常量,像"hello world"这种的给string赋值时:

如果输入的只有一个参数(字符串常量本身):str1.assign("hello world");

或者输入的是三个参数:str1.assign("hello world",1,8);

以上的两种赋值,跟①的结果是一样的。

但是!!!

如果输入的是两个参数,那么它的运行结果就跟①出现了不同。

举个栗子:

str1.assign("hello world",3);

最后str1="hel"而不会是"lo world"。

当只有两个参数的时候,输入的第二个参数实际上是size_count而不是index。

所以输入两个参数时,实际上默认index=0,也就是从字符串常量"hello world"的开头开始,然后截取前size_count个元素赋值给str1.

而在①的情况中,如果输入两个参数,默认的是从index开始(index为输入值),默认size_count是从index开始剩下的其他元素的个数。

③ 用n个相同的字符对字符串赋值

str1.assign(int n,char ch); 这个用法比较简单,我举个栗子大家就能明白了。

str1.assign(10,'a'); 执行完这个语句后,str1="aaaaaaaaaa" (10个a)

2.string的运算符及比较符

string支持 = , == , += , != , + 这几种运算符的操作

= 就是赋值作用,这一点在前面的初始化部分已经说明过了,相当于c语言中的strcpy函数。

== 和 != 就是用来比较两个字符串是否相等,作用相当于c语言中的strcmp函数。

+= 和 + 则可以用来为string赋值,这种赋值是添加性的,不会覆盖掉字符串原先的值。

string str="hello world";
string str1="qaq";
str1+=str;//执行完毕后,此时的str1="qaqhello world"
str1+='w';//执行完毕后,此时的str1="qaqhello worldw"
str1+="orz";//执行完毕后,此时的str1="qaqhello worldworz";

从上面的例子可以看出,+=这个符号不仅可以用在string类型,字符串常量和字符型也是同样适用的。

3.string的一些常用函数

① size()和length()

size函数返回的是字符串的大小,length返回的是字符串的长度,但是实际上它们的返回值是一样的,包括在cpp源码中的定义也是一样的,所以实际上没啥区别,喜欢用哪个就用哪个。

string str="hello"; 此时str.size()和str.length()的值都是5(字符串的长度).

② at()

at()函数的参数是at(int index),index是字符串的下标

在c语言中,我们要想遍历输出一个字符串数组,可以用到这样的代码:

for(i=0;i<len;i++)//len为字符数组str的长度
{
print("%c",str[i]);
}

那么在使用c++的string时,我们可以使用这样的代码来替换:

for(i=0;i<str.size();i++)
{
cout<<str.at(i);
}

相比较一下,我们马上就能发现,str.at(i)实际上和str[i]是一样的,只是表示的方法不同。

那么at()这个函数有什么好处呢?

at()函数是十分安全的,它会帮你检查下标是否越界,如果越界程序将无法运行,避免因为本次的越界情况导致更严重的错误,而如果用str[i]的表示方法,则没有办法保证安全性。

建议自己输出一下str.at(-1)这种肯定会越界的值,看看编译器会输出什么

③ find()

string除了find()以外,还有find_first_of这一类的函数,在此不做介绍

find() 一般用来查找子串,当然也可以用来查找单个字符是否在字符串中出现过。

如果在主串中找到了要查找的字串或者单个字符,那么会返回字串在主串中第一次出现的位置或是查找到的单个字符的位置。

如果没有找到,返回的值是 string::npos ,返回的值是 string::npos ,返回的值是 string::npos

重要的话要说三遍,这个返回值要怎么使用呢。

npos这个常量是定义为-1,但是npos的类型实际上是无符号数,所以npos实际上是这个类型正数的最大值。

说了这么多,来直接看一下例子吧:

string str="hello world";
string sub1="ell";
string sub2="wor";
string sub3="heo";
cout<<str.find(sub1)<<' '<<str.find(sub2)<<' '<<str.find(sub3);
/*
输出结果是1 6 4294967295
这里可以很明显发现,因为sub1和sub2都是可以找到的,返回的就是找到的第一个字符的下标
而sub3是找不到的,这个时候find函数的返回值是4294967295,也就是2^32-1(unsigned int 的最大值)
*/

从上面的代码中,可以很明显看出find的返回值是多少,那么如果我们用int或者long型的变量来接收find函数的这个返回值可不可行呢?

int i1,i2;
long i3;
i1=str.find(sub1);
i2=str.find(sub2);
i3=str.find(sub3);
cout<<i1<<' '<<i2<<' '<<i3;//输出的结果是 1 6 -1

我们都知道数据是依照补码的形式储存的,而2^32-1这个值储存到int和long类型的时候,代表的值都是-1,所以这个时候输出的值自然就是-1了。

看完上面两个例子,应该就知道要怎么使用find函数的返回值了,我们再举一个例子说明吧:

题目当你在str主串中寻找一个sub字串时,如果找到字串,输出yes,没有找到则输出no

string str="hello world";
string sub="hlo";//这里举一个找不到的例子
//写法1
if(str.find(sub) == string::npos)
{
cout<<"yes"<<endl;
}
else
{
cout<<"no"<<endl;
}
//写法2
int find;
find=str.find(sub);
if(find != -1)
{
cout<<"yes"<<endl;
}
else
{
cout<<"no"<<endl;
}
//写法三(错误写法!!)
if(str.find(sub) >= 0)
{
cout<<"yes"<<endl;
}
else
{
cout<<"no"<<endl;
}

在以上的三个写法中,前两个写法都是前面我们所提到的正确方法,第一个是直接与string::npos作比较,第二个则是用int类型或者long类型接收这个返回值,然后和-1作比较,这两种都是可行的。

那么我们来看看第三种写法:为什么if (str.find(sub) >= 0)这个判断语句是错误的呢

答案很简单,还记得我们上面提过,find函数如果没有找到,返回的值实际上是2^32-1,所以不管有没有找到字串sub,输出的都是"yes"。

那如果写成if(str.find(sub) == -1)这个判断语句呢?

答案其实是可行的,无符号数是没有负数的,所以碰到-1这个数的时候,实际上是和-1的补码作比较,而前面也提到过了,它的补码实际上和-1的就是相同的,所以这个判断是可以的。

总结一下:千万不能把判断语句写成if (str.find(sub) >= 0),如果是这么写,那么if条件实际上是永远成立的。

好了,上面花了很多的篇幅来详细解释了一下find函数的返回值问题,从我的个人角度来看,find函数的返回值还是挺有意思的,而且如果不清楚的话,很有可能在这里犯下难以被察觉的错误。

那么接下来来介绍一下find函数的一些常用的参数。

我们以string str="hello world",sub;这样的两个字符串为例,其中str是被初始化定义过的。

第一个用法就是上文一直在使用的str.find(sub),传入的参数是一个字符串,如果找到,那么返回的就是第一个下标的位置,如果没找到,返回值就是string::npos ,也就是-1。

当然除了传入字符串,传入单个的字符也是可以的:str.find('l')如果找到,返回的就是第一个l的下标值,在这里面就是2,如果没有找到返回的也是string::npos

那如果我在后面加上第二个参数呢?

str.find(sub,int index)那么这个函数要表达的意思就是:从下标index开始,搜索sub这个字串,如果搜索到该字串,返回第一个字符的下标值。

举一个例子:string str="hello world",sub="hel";

在这个时候,如果我们使用的是str.find(sub),那么我们得到的返回值就是0

而如果我们使用的是str.find(sub,3),那么我们得到的返回值就是string::npos(从下标3开始寻找,没有办法查找到sub字串)。

❗实际上,如果只输入第一个参数,第二个参数是默认为0的,也就是代表着从头开始查找

find函数是有第三个参数的,但是第三个参数的使用比较少见,这里暂时不作介绍

④ rfind()

rfind()函数实际上和find()函数是十分相似的,差别只在于它们的查找顺序不一样。