类型名 | 定义 | 类型 | 初始化 | c++11新特性 |
---|---|---|---|---|
string | 可变长度的字符型序列 | 类 | 1.string str1; //默认初始化,str1是一个空字符串; 2.string str1(str2); //str1是str2的副本; 3.string str1 = str2; //str1是副本;等价于2形式; 4.string str("hello"); //str是字面值“hello”的副本; 5.string str = "hello"; //;str是字面值“hello”的副本;等价于4; 6.string str = {'h','e','\0'}; //等价于4,5; 7.string str(n,'c'); //把str初始化为由连续n个字符'c'组成的字符串; | 1.cctype头文件,兼容C语言的头文件,其中含有一些字符处理函数; 2.使用基于范围的for语句,处理每个字符: for(declaration : expression) { statement } 含义:declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。 3.使用范围for语句改变字符串中的字符,需要用到引用,例如: for(auto & c : s) { c = toupper(c); }
|
vector<T> | 可变长度的T型 序列 | 类模板 (既不是类也不是函数) | 1.vector<T> s1; //默认初始化,s1是一个空vector,它潜在的元素是T类型; 2.vector<T> s1(s2); //s1是s2的副本; 3.vector<T> s1 = s2; //s1是副本;等价于2形式; 4.vector<T> s1{a,b,c,... }; //s1包含了初始值个数的元素,每个元素被赋予相应的初始值; 5.vector<T> s1 = {a,b,c,...}; //;等价于4; 6.vector<T> s1(n,val); //vec包含了n个重复的元素,每个值都是value; 7.vector<T> s1(n); //vec包含了n个重复的元素,每个值都是初始化值; *注意 ()、{}的使用不同: ()中的n代表个数;{}中的n代表内容。比如:vector<string> v5{"hello"};(√) vector<string> v6("hello");(×)不能用字符串字面值构建 vector 对象。 8.使用数组初始化 vector 对象 int int_arr[] = {0,1,2,3,4,5}; vector<int> ivec(begin(int_arr),end(int_arr)); | 1.头文件vector,可运用vector的成员函数push_back向其中添加元素。push_back负责把一个值当成vector对象的尾元素“压入push”到vector对象的“尾端(back)”。 v.empty(),如果v不含有任何元素,返回真;否则返回假。 v.size(),返回v中的元素个数。 支持 =、==、!=、<、<=、>、>= 操作 注意:只能对下标已经存在的元素执行索引。通过下表访问不存在的元素的行为会导致缓冲区溢出(buffer overflow)错误。 2.使用基于范围的for语句,处理每个字符: for(declaration : expression) { statement } 含义:declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。 3.使用范围for语句改变字符串中的字符,需要用到引用,例如: for(auto & c : s) { c = toupper(c); } |
一、举例
1.使用基于范围的for语句:
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
using namespace std;
int main()
{
vector<int> a(10,2);
for(auto & temp : a)
{
temp *= 2;
}
for(auto temp : a)
{
cout<<temp<<"\t";
}
cout<<endl<<"------------------------------------------------------"<<endl;
vector<string> str{10,"hi"};
for(auto arr : str)
{
cout<<arr<<endl;
}
return 0;
}
2.从cin读入一组词并把它们存入一个vector对象,然后设法把所有词都改写为大写形式。输出改变后的结果,每个词占一行。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> str;
string temp;
while(cin>>temp)
{
for(auto & c : temp)
{
c -= 32;
}
str.push_back(temp);
}
for(int i = 0;i < str.size();i++)
{
cout<<str[i]<<endl;
}
return 0;
}
注意:试想在while循环中,先执行str.push_back(temp),再执行基于范围的for语句可以吗?
答:不可以,因为push,相当于是一个压入栈的操作,会将内容压入到向量中,那么此时temp就为空了,然后逐个去操作空内容,也就没有了什么意义。
3.读入一组整数并把它们存入一个vector对象,将每对相邻整数的和输出出来。改写你的程序,这次要求先输出第一个和最后一个元素的和,接着输出第二个和倒数第二个元素的和,以此类推。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> a;
int temp;
while(cin>>temp)
{
a.push_back(temp);
}
for(int i = 0;i < a.size()/2;i++)
{
cout<<a[i] + a[a.size() - i - 1]<<endl;
}
if(a.size() % 2 == 1)
{
cout << a[a.size()/2]<<endl;
}
return 0;
}
二、迭代器(又称游标)
类 | 对象 | iter |
容器 | 迭代器对象(的地址) | *iter |
类似于指针类型,迭代器也提供了对对象的间接访问。对string对象的字符和vector对象的元素的访问机制:
- 下标运算符
- 迭代器(除vector之外,在标准库中定义的几种容器也可以使用迭代器,但是其中只有少数几种也可以使用支持下标运算)
注意:string对象不属于容器类型,但是string支持很多与容器类型类似的操作。vector支持下标运算符,这点和string一样;string支持迭代器,这也和vector一样。
1. 使用迭代器
和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员。比如,这些类型都拥有名为begin和end的成员,其中begin成员负责返回指向第一个元素(或第一个字符)的迭代器。end成员则负责返回指向容器(或string对象)“尾元素的下一个位置”的迭代器,也就是说,该迭代器只是的是容器的一个本不存在的“尾后(off the end)”元素。这样的迭代器没什么实际含义,仅是个标记,表示我们已经处理完了容器中的所有元素。end成员返回的迭代器常被称为尾后迭代器或者称为尾迭代器。
auto b = v.begin(),e = v.end(); //b和e的类型相同
如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。
迭代器运算符
*iter //对iter进行解引用,返回迭代器iter指向的元素的引用 iter->men //对iter进行解引用,获取指定元素中名为men的成员。等效于(*iter).men ++iter //给iter加1,使其指向容器的下一个元素 iter++ --iter //给iter减1,使其指向容器的前一个元素 iter-- iter1==iter2 //比较两个迭代器是否相等,当它们指向同一个容器的同一个元素或者都指向同同一个容器的超出末端的下一个位置时,它们相等 iter1!=iter2
举例:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> str;
string temp = "hello";
str.push_back(temp);
vector<string>::iterator str1;
str1 = str.begin();
cout<<(*str1)<<endl;
cout<<(*str1)[0]<<endl; //你猜猜输出啥:h
return 0;
}
迭代器就是地址,如果想获取其内容,需要对其解引用。
迭代器运算
几点注意事项:
- 已知一个限制的 vector 对象,是不能在范围 for 循环中向 vector 对象添加元素。
- 任何一种可能改变 vector 对象容量的操作,比如 push_back,都会使该vector对象的迭代器失效。
- 谨记,但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。
- 不允许使用一个数组为另一个内置类型的数组赋初值。
- 不允许使用 vector 对象初始化数组,但是可以使用数组初始化vector对象。
eg1:
int int_arr[] = {0,1,2,3,4,5};
// ivec 有6个元素,分别是int_arr中对应元素的副本
vector<int> ivec(begin(int_arr),end(int_arr));
eg2:
vector<int> subVec(int_arr + 1,int_arr + 4);
//subVec是一个有3个元素的对象,分别是int_arr[1]、int_arr[2]、int_arr[3]
三、删除元素
c.pop_back() | 删除c中尾元素。若c为空,则函数行为未定义。函数返回void。 |
c.pop_front() | 删除c中首元素。若c为空,则函数行为未定义。函数返回void。 |
c.erase(p) | 删除迭代器p所指定的元素,返回一个纸箱被删元素之后元素的迭代器,若p指向尾元素,则返回尾后(off-the-end)迭代器。若p是尾后迭代器,则函数行为未定义。 |
c.erase(b,e) | 删除迭代器b和e所指定范围内的元素。返回一个指向最后一个被删元素之后元素的迭代器,若e本身就是尾后迭代器,则函数也返回尾后迭代器。 |
c.clear() | 删除c中的所有元素。返回void。 |
注意:
- pop_front和pop_back成员函数分别删除首元素和尾元素的时候,不会返回该值,如果想保存该值,需要在弹出操作之前进行保存操作。
- 删除多个元素方法有两种:
1)使用erase(elem1,elem2)删除一个范围内的元素:
// 删除两个迭代器表示的范围内的元素:[ , )
// 返回指向最后一个被删元素之后位置的迭代器
elem1 = slist.erase(elem1,elem2);
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
deque<int> que;
int temp;
while(cin>>temp)
{
que.push_back(temp);
}
sort(que.begin(),que.end());
for(int i = 0;i < que.size();i++)
{
cout<<que[i]<<"\t";
}
cout<<endl;
que.erase(que.begin());
for(int i = 0;i < que.size();i++)
{
cout<<que[i]<<"\t";
}
cout<<endl;
return 0;
}