容器
1.
String
String是C++风格的字符串,其本质上是一个类,内部封装了char*。
1.1
构造函数与赋值函数
String作为一个类自然具有构造函数以及重载的operator=()函数,而这些函数则代表了一个string对象及有哪些初始化的方式。
首先,其构造函数包含以下几个:
- string(); ------无参构造,用于创建一个空的字符串
- string(const char* s);------一种有参构造,使用字符串常量对string类型对象进行初始化
- string(const string& str);------拷贝构造,使用一个string对象初始化另一个对象
- string(int n, char c);------使用n个字符c初始化string对象
具体使用方式可以参考曾经写过的类型初始化的文章,这里简单列举一下:
string s1; //利用默认构造创建空的string对象
string s2("asbjkg"); //利用字符串常量初始化s2
string s3(s2); //将s2的副本赋值给s3
string s4(3,'c'); //s4="ccc"
String赋值操作的函数有重载的operator=()函数和assign()函数:
- string& operator=(const char* s);------利用字符串常量赋值
- string& operator=(const string& s);------利用string对象赋值
- string& operator=(char c);------利用字符赋值
- string& assign(const char* s);------利用字符串常量赋值
- string& assign(const char* s,int n);------将字符串s的前n个字符赋给当前对象
- string& assign(const string& s);------将字符串s赋给当前字符串
- string& assign(int n,char c);------将n个字符c赋值给string对象
示例:
string s1="sdks";
string s2=s1;
string s3='c';
string s4;
s4.assign("sohfs");
string s5;
s5.assign("fskhs",3);
string s6;
s6.assign(s5);
string s7;
s7.assign(3,'c');
以上示例分别对应前面所列举的赋值函数。
1.2
方法与函数
1.2.1 字符串拼接
这一节讲述如何在字符串尾部拼接另一个字符串。
具有此功能的函数包括重载的+=操作符:
- string& operator+=(const char* s);
- string& operator+=(const char c);
- string& operator+=(const string& s);
PS:事实上,除了重载的+=操作符,还有重载的+运算符也可以进行字符串的拼接。
但是,如果用+运算符的话,必须保证+号左右两侧 至少有一个是string对象。
string s1 = "sjkfks";
string s2 = "klll";
string s3 = s1 + s2; //这是合法的
s3 = s1 + "fsf"; //这也是合法的,+号左侧为string对象
s3 = "fsdhjf" + s2; //同样合法
s3 = "fsk" + "kjf"; //非法,因为均为字面值常量,无法自动转换为string对象
这种错误往往出现在连续+号的地方:
string s4 = "hello " + ',' + s1; //由于第一个+号左右两侧均为字面值常量,因此出现了错误
在这里我们需要切记的是,C++的string对象并不是字符串字面值,从以上的例子可以看出,它们并不是一个概念。往往我们可以用字符串字面值初始化string对象,这是因为编译器帮我们做了一个 隐式类型转换 。
以及append()函数:
- string& append(const char* s);
把字符串s连接到当前字符串尾部 - string& append(const char* s,int n);
把s的前n个字符连接到当前字符串的尾部 - string& append(const string& s);
- string& append(const string& s,int pos,int n);
s中从pos开始的n个字符连接到字符串结尾
这里就不展示示例了。暂时没想到什么需要注意的点。
1.2.2 查找与替换
查找用于寻找指定的字符串是否存在;替换用于在指定的位置替换字符串。
查找的函数包括find(),rfind():
- int find(const string& str, int pos=0) const;
查找str第一次出现的位置,从pos开始找;pos默认从首位开始;返回str第一个字符所在的位置。 - int find(const char* s,int pos = 0) const;
查找字符串s第一次出现的位置,从pos开始找;pos默认从首位开始;返回s所在的位置。 - int find(const char* s,int pos,int n) const;
从pos位置开始查找s的前n个字符第一次出现的位置。 - int find(const char c,int pos = 0) const;
查找字符c第一次出现的位置,从pos开始查找;pos默认首位。 - int rfind(const string& str, int pos = npos) const;
- int rfind(const char* s, int pos = npos) const;
- int rfind(const char* s, int pos, int n) const;
- int rfind(const char c, int pos = 0) const;
注意,find()函数倘若没有找到想查找的字符串,则会返回-1。
find()与rfind()的区别在于 find()正向查找,而rfind()逆向查找 。
string str1 = "abcdefgdeg";
int pos_f = str1.find("de");
int pos_rf = str1.rfind("de");
cout << "pos_f= " << pos_f << endl; //输出pos_f = 3
cout << "pos_rf= " << pos_rf << endl; //输出pos_rf = 7
替换的函数为replace():
- string& replace(int pos, int n, const string& str);
替换从pos开始的n个字符为字符串str - string& replace(int pos, int n, const char* s);
string str1="abcdefg";
str1.replace(1,3,"4234");
cout << str1 << endl; //输出为 a4234efg
1.2.3 字符串比较
字符串之间的比较是利用字符的ASCII码进行大小的判定的。具有以下几个规则:
- 如果两个string对象的长度不同,而且较短string对象的每个字符都与较长string对象对应位置上的字符相同,则认为较短的string对象小于较长的string对象;
- 如果两个string对象在某些对应的位置上不一致,则string对象比较的结果其实是第一对相异字符的比较结果;
- 字符的比较根据ASCII码进行判定。
比较函数是compare(),倘若相等则返回0;大于则返回1;小于则返回-1:
- int compare(const string& s) const;
与字符串s比较大小 - int compare(const char* s) const;
利用重载的运算符也可以比较两个字符串是否相等:
s1 == s2;
s1 != s2;
s1 < s2;
1.2.4 其余操作
- 单个字符的读写
string中单个字符的读写方式有两种:
- char& operator[](int n);
通过重载的[]运算符获取第n位的字符,下标从零开始计算。 - char& at(int n);
用法与[]类似,通过at方法进行字符的读取。
可以通过这两种方式读取string对象中的字符:
string s1 = "abcdefg";
for(int i = 0; i != s1.size(); ++i)
{
//这两个的结果是一致的
cout << s1[i] << endl;
//cout << s1.at(i) << endl;
}
也可以通过这两种方式修改string对象中的字符:
s1[2] = s;
s1.at(3) = g;
- 插入与删除字符
插入和删除的函数为insert()与erase():
-
string& insert(int pos, const char* s);
在指定的pos位置前插入字符串s -
string& insert(int pos, const string& str);
-
string& insert(int pos, int n, char c);
在指定位置前插入n个字符c -
string& erase(int pos, int n=npos);
删除从pos开始的n个字符示例:
string s = "hello"; s.insert(2,"qwer"); //输出为 heqwerllo cout << s << endl; //可以看出,在第二个位置前即l之前插入了qwer s.erase(2,4); cout << s << endl; //输出为hello
- empty()与size()方法
empty根据string对象是否为空返回一个对应的布尔值,如果为空,则返回true。
size返回string对象的长度。
对于size函数来说,其返回的值的类型并非int亦或unsigned,而是一个string::size_type类型值。
size_type是标准库定义的一个配套类型,体现了标准库类型与机器无关的特性。它是一个无符号类型值,且可以存放任何string对象的大小。理论上我们应该使用string::size_type类型存放size函数返的值。
因此,我们建议,如果一条表达式中已经有了size函数,就不要使用int了。这样可以避免混用int和unsigned可能带来的问题,比如若n < 0,则s.size() < n几乎可以肯定是true了,因为负值n会自动换为较大的无符号值。这还是该死的类型转换带来的问题。
- 处理string对象中的字符
上面说过如何通过[]运算符和at()方法读取string对象的字符,这边讲的是一些处理字符相关的函数。
头文件cctype中定义了一组标准库函数处理这些工作。
|
|
---|---|
isalnum(c) | 当c是字母或数字时为真 |
isalpha(c) | 当c是字母时为真 |
iscntrl(c) | 当c是控制字符时为真 |
isdigit(c) | 当c是数字时为真 |
isgraph(c) | 当c不是空格但可以打印时为真 |
islower(c) | 当c是小写字母时为真 |
isprint(c) | 当c是可打印字符时为真 |
ispunct(c) | 当c是标点符号时为真 |
isspace(c) | 当c是空白时为真 |
isupper(c) | 当c是大写字母时为真 |
isxdigit(c) | 当c是16进制数时为真 |
tolower(c) | 若c是大写字母,将其变为小写字母;否则原样输出 |
toupper(c) | 与tolower相反的操作 |
如果想对string对象中的每个字符做点啥操作,目前最好的办法是利用C++11提供的范围for语句。
//一个例子
for(auto &c : str)
{
c=toupper(c); //将str中每个字符变为大写
}
如果想对string对象的一部分进行操作,那么可以使用下标索引和迭代器。
其实严格地说string对象不属于容器类型,但是string对象支持很多与容器类似的操作,迭代器就是一个例子。迭代器的使用目前还未学习,将会放在以后写下来。
- 子串获取
string对象的子串获取可以使用substr()方法。
- string substr(int pos=0, int n=npos);
返回由pos开始的n个字符组成的字符串
这是一个比较实用的方法,比如说如果我们有很多邮箱账号,然后我们需要截取所有邮箱账号的用户名就可以用这个方法。
string str = "zhangsan@qq.com";
int pos = find('@');
string subs = str.substr(0,pos);
2.
Vector
Vector数据结构与数组很相似,但是vector可以动态扩展,而数组是一段静态的空间。
所谓动态扩展,并非是在原空间后接续新空间,而是寻找跟大的新空间,将原数组拷贝到新空间并释放原空间。这一点与之前设计的指针控制的数组有相似之处。
Vector本身是一段左闭右开的链式内存区间,它只支持在容器的尾部添加元素。
另外,vector的迭代器是支持随机访问的迭代器。
2.1
构造函数与赋值函数
vector的构造函数的原型大概有这么几种:
- vector<T> v;
默认构造函数,采用模板制作的类。 - vector(v.begin(),v.end());
将v的begin()到end()区间内的元素拷贝过来,区间范围是左开右闭。 - vector(n,elem);
构造函数将n个elem拷贝给本身。 - vector(const vector &vec);
拷贝构造函数。
示例:
vector<int> v1; //默认构造函数构建一个空的对象
for(int i=0; i!=10;++i)
{
v1.push_back(i); //利用push_back方法在容器尾部添加元素
} //这样就构造了一个含有十个元素的vector<int>对象
vector<int> v2(v1.begin(),v1.end(