zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【C++】string容器&vector容器

C++amp容器 string vector
2023-09-11 14:19:30 时间

目录

string容器

基本概念:

构造函数:

赋值操作:

 追加操作:

查找、替换操作:

 删除、插入操作:

对比操作:

存放操作:

获取子串操作:

vector容器

构造函数:

赋值操作:

容器大小和容量操作:

容器的插入和删除:

存放操作:

互换容器操作:

预留空间操作:


string容器

基本概念:

string就是C++中的字符串类型,它的本质还是一个类,它封装了一个char*类型的指针。就像我们C语言中用字符指针来维护字符串;C++中用封装好的类string来维护字符串类型。

构造函数:

string容器可以有4种构造函数的使用方法:

1.调用无参构造:直接在字符串类型后面定义一个常量字符串;

2.调用有参构造:第一个参数传递字符串字符个数,第二个参数传递字符。可以构造重复字符字符串;

3.调用拷贝构造:直接往字符串类型里传一个字符串类型变量;

4.调用有参构造:传递一个const char*类型变量维护的字符串指针;

	//字符指针维护的字符串类型;
	const char* s0 = "abced";
	//字符串类型无参构造;
	string s1="abcde";
	//字符串类型有参构造,第一个参数字符串的字符个数,第二个参数字符串的字符;
	string s2(5,'a');
	//字符串类型拷贝构造;
	string s3(s1);
	//字符串类型有参构;
	string s4(s0);

赋值操作:

在string容器中,我们可以利用等号来赋值操作,也可以利用string里的assign成员函数来进行赋值操作;

“=”赋值:

1.直接赋值常量字符串;

2.赋值string类型;

3.赋值单个字符类型;

成员函数assign赋值:

1.赋值常量字符串;

2.赋值string类型;

3.赋值常量字符串前n个字符;

4.赋值n个字符x;

    //等号赋值常量字符串;
	string s1;
	s1 = "hello";
    //等号赋值string类型;
	string s2;
	s2 = s1;
    //等号赋值单个字符;
	string s3;
	s3 = 'a';
    //assign函数赋值string类型
	string s4;
	s4.assign(s1);
    //assign函数赋值常量字符串前n个字符;
	string s5;
	s5.assign("hello", 2);
    //assign函数赋值常量字符串;
	string s6;
	s6.assign("hello");
    //assign函数赋值n个字符x;
	string s7;
	s7.assign(5,'a');

 追加操作:

string类型维护的是字符串类型,所以很自然的就会有追加字符串的操作。追加字符串也有两种方法:“+=”追加和append成员函数。

“+=”操作:

1.+=后追加常量字符串;

2.+=后追加string类型;

3.+=后追加字符;

append成员函数;

1.append里放常量字符串;

2.append里放string类型;

3.append里放第一个参数是常量字符串,第二个参数是整型n,表示从常量字符串中复制n个字符追加到原字符串后;

4.append后跟三个参数,第一个是字符串类型,第二个是复制的字符在字符串类型中起始位置,第三个参数是要复制的字符个数;

	string s1;
	s1 = "ab";
	//+=常量字符串
	s1 += "cd";
	string s2 = "cd";
	//+=string类型
	s1 += s2;
	//++字符类型
	s1 += 'c';
	//append里跟常量字符串
	s1.append("cd");
	//append里跟string类型
	s1.append(s2);
	//append里跟常量字符串及复制个数
	s1.append("cde", 1);
	//append里跟string类型及复制起始位置和复制个数
	s1.append(s2, 0, 1);

查找、替换操作:

C++中string容器对查找提供了两个成员函数find和rfind;两个函数互不相同,find是从左往右查找,rfind是从右往左查找。它们的参数都是要查找的字符串,返回类型都是要查找的字符串在被查找的字符串的下标,一旦找到就退出;找不到就返回-1;

而替换操作使用成员函数replace,它有三个参数,第一个是字符串中被替换的字符起始位置,第二个是被替换的字符个数,第三个是替换上去的字符串;

    //查找
	string s1 = "abcdefg";
	s1.find("ab");
	s1.rfind("ab");
	//替换
    const char* s2 = "aaaaa";
	s1.replace(0, 6, s2);

 删除、插入操作:

string容器中的删除和替换操作分别利用erase和insert成员函数;

insert成员函数有两个参数,第一个是要插入字符串的起始位置,第二个是要插入的字符串;

erase成员函数有两个参数,第一个要删除的字符串的起始位置,第二个是要删除的字符串包含的字符个数;

	string s1 = "abcedf";
    //插入
	s1.insert(2,"wwwww");
	cout << s1 << endl;
    //删除
	s1.erase(5, 2);
	cout << s1 << endl;

对比操作:

字符串的对比利用string容器的compare函数,它有一个参数,就是要比较的字符串。比较方式是从左往右一个字符一个字符的ASCII码值比较,不比字符串长度!要是比较的字符串比参数字符串大,返回1;相等返回0;比较的字符串比参数字符串小,返回-1;

	string s1 = "abcd";
	string s2 = "abcf";
	if (s1.compare(s2) == 0)
	{
		cout << "s1=s2" << endl;
	}
	else if (s1.compare(s2) > 0)
	{
		cout << "s1>s2" << endl;
	}
	else
	{
		cout << "s1<s2" << endl;

	}

存放操作:

对于string字符串的存放,我们也可以利用类似于用数组下标访问字符串单个字符的方法来访问string里的单个字符,这里有两种方法:“[ ]”下标访问和at成员函数下标访问;

这里可以理解为“[ ]”和at成员函数功能类似!

	string s1 = "abcdef";
	s1[2] = 'g';//将第三个字符c修改为g
	s1.at(0) = 'h';//将第一个字符a修改为h

获取子串操作:

在string容器中,我们获取字符串类型的子串可以通过成员函数substr,它的参数有两个,第一个是获取的子串的起始位置,第二个是获取到子串的字符个数;这里有个扩展:字符串类型有个成员函数size可以获取当前字符串的长度!

	string s1 = "abcdef";
    //获取3个字符bcd;
	string s2 = s1.substr(1, 3);
	cout << s2 << endl;

vector容器

vector容器的行为类似数组,我们也可以将其类似看成是一个单向的数组,但是它不是数组,它是可以动态扩增的,而vector容器的前端是固定的。若我们对vector容器管理的内存空间进行容量增加时,容器不会继续往后扩增,因为它也不知道后面的内存是否已经被占用,所以它会向另一块空间申请内存。

构造函数:

关于vector的构造函数有4类:

1.无参构造函数;

2.拷贝构造函数,传递的参数是一个vector类型的容器变量;

3.有参构造函数,传递的第一个参数是另一个vector的起始位置(即.begin());传递的另一个参数是另一个vector的末尾位置的下一个位置(即.end());

4.有参构造函数,第一个参数是数据,第二个参数是同样数据的份数;

 	//默认构造函数
    vector<int> v1;
	for (int i = 0; i < 3; i++)
	{
		v1.push_back(i);
	}
    //拷贝构造函数
	vector<int> v2(v1);
    //有参构造函数
	vector<int> v3(20, 100);
    //有参构造函数
	vector<int> v4(v1.begin(), v1.end());

赋值操作:

vector的赋值操作与string类似,也可以有等号和assign函数;它们加起来共有三种方式:

1.等号赋值,直接v1=v2;

2.assign函数赋值,第一个参数为赋值容器的起点,第二个参数为复制容器的终点的后一位;

3.assign函数赋值,第一个参数为要赋予的数据的个数,第二个参数为赋予的值;

	vector<int>v1;
	for (int i = 0; i < 6; i++)
	{
		v1.push_back(i);
	}
    //等号赋值;
	vector<int>v2;
	v2 = v1;
    //assign第一种赋值;
	vector<int>v3;
	v3.assign(v1.begin(), v1.end());
	//assign第二种赋值;
    vector<int>v4;
	v4.assign(3, 1);

容器大小和容量操作:

所谓容器的大小和容量,我们可以将其比喻为一个瓶子里的水和一个瓶子;瓶子就是容量,大小就是现在瓶子里的水。瓶子永远会比瓶子里的水体积大;同理,容量也会始终比大小要大。那么我们下面来看看几个有关容量和大小的操作:

1.empty成员函数:empty成员函数是用来判断容器是否为空,即大小是否为0,里面是否有水;

2.capacity成员函数:这个函数是获取当前容器的容量的函数;

3.size成员函数:这个函数是获取当前容器大小的函数;

4.resize成员函数:这个函数是用来增长或者缩短容器大小的函数!注意,不是容量!它的参数为变化后容器的大小。这个函数也有一些需要注意的地方:1.如果增长容器的大小,后续超出部分自动用0补齐,如果操作者不想用0,也可以指定resize的第二个变量为要补上去的数;2.如果要缩短容器,那么在原有数据基础上会丢失后面的数据。

	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(2 * i);
	}
    //判断是否为空
	if (v1.empty())
	{
		cout<<"is empty" << endl;
	}
	else
	{
		cout<<"not empty" << endl;
	}
    //获取大小
	cout<<v1.size()<<endl;
    //获取容量
	cout<<v1.capacity()<<endl;
	//一般增长
    v1.resize(20);
	cout << v1.capacity() << endl;//20
	//一般缩短
    v1.resize(3);
	cout << v1.capacity() << endl;//20
    //后面补数
	v1.resize(20, 1);

容器的插入和删除:

对于vector容器的插入和删除操作,我们利用insert进行插入,利用erase进行删除,并且我们还可以利用clear进行清空操作;

insert:它有两种使用方式,第一种是直接利用迭代器指定位置进行插入;第二种是利用迭代器指定位置,然后指定插入个数和元素;

erase:它有两种使用方式,第一种是直接利用迭代器找到位置元素进行删除;第二种是利用迭代器找到两个位置,删除中间的元素(注意区间是前闭后开)

	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
    //在第二个数前插入6
	v1.insert(v1.begin()+1,6);
	print(v1);
    //在第3个数前插入两个2
	v1.insert(v1.begin() + 2, 2, 2);
	print(v1);
    //删除第4个元素
	v1.erase(v1.begin()+4);
	print(v1);
    //删除第1个到第2个元素
	v1.erase(v1.begin() + 1, v1.begin() + 3);
	print(v1);
    //清空
	v1.clear();
	print(v1);

我们也可以利用push_back()、pop_back()两个函数进行尾插和尾删:

	v1.push_back();
	v1.pop_back();

存放操作:

类似string容器,vector容器也可以利用类似数组下标的访问方法访问到里面的元素。我们可以利用  [ ]at成员函数来访问;同时,vector容器还有一个front函数访问头元素和back函数来访问尾元素。

	//[ ]访问
    cout<<v1[4]<<endl;
	//at成员函数访问
    cout << v1.at(4) << endl;
	//front成员函数访问首元素
    cout << v1.front() << endl;
	//back成员函数访问尾元素
    cout<<v1.back()<<endl;

互换容器操作:

容器互换我们用的是swap成员函数,它有一个参数,参数类型就是容器类型,调用这个函数可以将调用者与被调用者进行容器交换;

	vector<int> v1;
	v1.push_back(2);
	v1.push_back(2);
	v1.push_back(2);
	v1.push_back(2);
	v1.push_back(2);
	vector<int>v2;
	v2.swap(v1);

容器调换有一个实用的用途,它可以进行内存收缩,即当我们申请的容器容量过大,而我们容器大小不需要这么大,这时候我们可以利用匿名对象和容器互换来实现内存收缩。具体是创建一个匿名对象,然后将匿名对象与原来容器进行交换,此时就能获得一块适合大小的容量的容器;

	vector<int>(v1).swap(v1);

预留空间操作:

我们在开辟内存空间时,容器也会随之动态扩展,那么如果当我们开辟的空间比较大,那么容器就会不断扩展空间。特别是当空间很大时,容器扩展的次数就会比较多。为了解决这个问题,我们引入了一个成岩函数reserve。这个函数可以提早告诉编译器我需要开辟那么多空间,那么当我们用容器时,容器只需要开辟一次就可以了。

//预留10个数据类型大小的内存空间
v1.reserve(10);