C++ STL引入+string(介绍)
- 一.STL引入:
- 1.什么是STL
- 2.什么是STL的版本:
- 2-1:原始版本:
- 2-2:P. J 版本:
- 2-3:RW 版本:
- 2-4:SGL版本:
- 3.STL 的六大组件:
- 4.STL的意义:
- 二.string类:
- 1.string 类:
- 2.流插入和流提取操作符:
- 3.赋值操作符:
- 4.string类的常见构造:
- string()
- string(const char*)
- string(size_t n,char C)
- string(const string& s) :拷贝构造
- string(const string& s,size_t pos,size_t len = npos):范围拷贝
- 补充:析构函数是自动调用的。
- 5.容量相关的代码:
- size() :返回字符串有效字符串长度数
- length() :返回字符串有效字符串长度数
- max_size():返回类可以开辟的空间最大的数值:
- capacity():返回空间总大小:
- capacity 检测代码:
- empty():判断字符串是否为空串,空返回true ,不为空返回false
- clear()清空有效字符
- reserve()为字符串预留空间
- resize() 将有效字符改成n个并且多的使用字符C填充
- 6.string 类对象的遍历:
- 6-1:通过重载的[]下标访问操作符:
- 6-2:通过iterator迭代器实现遍历:
- 6-3:通过string 的迭代器可以类比其他的容器的迭代器:
- 6-4:通过范围for实现遍历:
- 7.元素访问:
- operator[]
- at
- 8.修改方面的方法:
- append
- operator+= 好处:
- 9.两个算法:
- 7-1:逆置算法:reverse()
- 7-2:交换算法:
- 8:四个练习题:
- 8-1:把字符串转换成整数:
- 8-2:反转字符串:
- 8-3:字符串中第一个唯一字符:
- 8-4:字符串相加:
一.STL引入:
1.什么是STL
STL(standard template libaray 标准模板库):是C++ 标准库(还包括有IO库:智能指针库:)的重要组成部分,不仅仅是一个可以复用的组件库,而且还是一个包含数据结构与算法的软件框架。
2.什么是STL的版本:
2-1:原始版本:
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。
唯一的条件就是也需要向原始版本一样做开源使用。(如果你写了一个库是基于STL的内容进行的修改那么这个库需要进行开源)
……
HP 版本–所有STL实现
2-2:P. J 版本:
由P.J plauger 开发,继承自hp版本,windows visual C++ 采用,不可以公开和修改。
2-3:RW 版本:
由Rouge Wage 开发,继承自hp版本,被C++ buider 采用,不可以公开或者修改。
2-4:SGL版本:
由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。我们后面学习STL要阅读部分源代码,主要参考的就是这个版本。
3.STL 的六大组件:
4.STL的意义:
STL是C++中重要的作品有了STL许多底层的数据结构和算法都不需要自己重新造轮子。可以让我们站在巨人的肩膀上进行快速高效的开发!
总结:STL学习的三个境界:能用,明理,能扩展。
二.string类:
引入:在C语言中,字符串是用\0结尾的一串字符的集合,为了方便操作C语言提供了一系列的字符串系列的函数,但是这些库函数是和字符串是分离开来的不符合面向对象的思想,并且字符串空间的数据需要用户自己管理和释放容易导致产生越界访问!
1.string 类:
1.我们会发现string类是由一个basic_string 一个类模板实例化生成的一个类的typedef 重命名的。
2.使用需要带头文件()和 using namespace std;
2.流插入和流提取操作符:
string类重载了流插入和流提取操作符,他们是类的友元函数。
运行代码可以得到几个结论:
1.cout正常打印字符串内容包括空格:
2.cin不可以插入中间存在空格的字符串,只能把第一个空格之前的内容输入进字符串对象中。
3.赋值操作符:
支持:
string=string
string = const char*
string = char
4.string类的常见构造:
string()
构造空的字符串类对象
string(const char*)
用常量字符串构造string对象:
string(size_t n,char C)
个数+字符的形式的构造函数:
string(const string& s) :拷贝构造
string(const string& s,size_t pos,size_t len = npos):范围拷贝
1.从s的pos位置开始拷贝len个字符到新的字符串里面去!
2.npos的默认缺省值为-1 但是因为len类型为size_t 类型所以默认值是非常大的!
3.len的值比较大的时候如果被拷贝的字符串后面没有字符了就不会拷贝了!
补充:析构函数是自动调用的。
5.容量相关的代码:
size() :返回字符串有效字符串长度数
length() :返回字符串有效字符串长度数
总结:为什么有两个方法都可以计算字符串的有效字符个数,因为STL库的出现没有string这个类早,早的时候使用的是length计算个数。后来STL库出来之后使用size方法计算各种类的元素个数所以又给string类添加了一个方法用来计算有效字符个数。
ps:下面内容后面会补充
max_size():返回类可以开辟的空间最大的数值:
总结:可以开辟的最大空间的大小是根据不同位数区分但是不止于此在不同的编译器下也会不一样
注意:方法美其名日可以开辟这么大的空间但是是开辟不了这么大的空间的下面可以进行验证:
capacity():返回空间总大小:
在vs下:
在sgl下:
1.在g++下默认空字符串是不会去开空间就是不存在默认空间。
capacity 检测代码:
在vs下检测扩容机制:
在sgl下检测扩容机制:
1.默认从0开始,第一个数据进来开一个空间,然后开两个,到4个一直以二倍进行扩容:
empty():判断字符串是否为空串,空返回true ,不为空返回false
clear()清空有效字符
reserve()为字符串预留空间
1.主要作用:就是进行容量的预开辟,前提是知道需要多大的空间:
2.我们知道默认16(包含\0),设置当前容量为20,打印的结果是31是因为,底层需要对齐的操作。(除非设置好空间的大小值是满足对齐要求的否则实际的空间大小会比设置的大一点!)
3.我们发现reserve(在vs)不可以进行容量的减少只能进行容量的增加并且影响不到原来数据。
4.总结:只能进行扩容,不可以进行分段释放。
1.主要作用:就是进行容量的预开辟,前提是知道需要多大的空间:
2.我们知道默认16(包含\0),设置当前容量为20,打印的结果是31是因为,底层需要对齐的操作。(除非设置好空间的大小值是满足对齐要求的否则实际的空间大小会比设置的大一点!)
3.我们发现reserve(sgl)可以进行容量的减少只要不去影响到原来的数据。
4.总结:只能进行扩容,不可以进行分段释放。
resize() 将有效字符改成n个并且多的使用字符C填充
1.resize 有两个重载:直接改变有效字符的个数用\0填充,\0不可见。
2.直接改变有效字符的个数用C填充。
1.有效字符变大:size_1 < n < capacity_1
2,进行尾插。
1.n<size()
尾删,删到剩n个数据,容量空间不会改变:
1.n>capacity_1
2.容量空间可以进行扩容
3.有效字符可以自己设置!
6.string 类对象的遍历:
6-1:通过重载的[]下标访问操作符:
基本使用:
循环遍历操作:
总结:通过重载的下标范围操作符是不可以进行内存空间的跳跃访问(比如链表:树:图:哈希等)的所以存在iteratoriterator迭代器实现遍历。
6-2:通过iterator迭代器实现遍历:
1.iterator 是一个类型(类似指针类型,指针指向对象的成员。)被类限定但是不被访问限定符限定:
2.通过类名+访问限定符进行访问。
3.类提供了方法去返回头尾指针(类似地址的东西)。
1.可读可写:
2.只读:
总结:返回的访问指针begin() end() 是满足左闭右开的!
6-3:通过string 的迭代器可以类比其他的容器的迭代器:
顺序表:
列表:
6-4:通过范围for实现遍历:
7.元素访问:
operator[]
at
总结:
1.operator[]的下标访问越界报错是直接报错误:
2.使用at 产生越界问题会只会去抛出异常可以进行异常捕获然后打印:
8.修改方面的方法:
append
1.append()重载了6个方法:
2.内容非常的冗余:完全没有必要;
operator+= 好处:
1.可以在当前字符串后面添加字符串:
2.可以在当前字符串后面添加一个直接写的 const char*
3.可以在当前字符串后面添加一个字符:
9.两个算法:
7-1:逆置算法:reverse()
字符串的逆置:
7-2:交换算法:
考虑使用迭代器和循环遍历实现一个逆置:
8:四个练习题:
8-1:把字符串转换成整数:
题目链接:
class Solution {
public:int StrToInt(string str){string::iterator it = str.end();int count = 1;int sum = 0;while (it != str.begin()){it--;char tmp = (*it);if (tmp >= 48 && tmp <= 57){sum += (((int)(tmp - '0')) * count);}else{if (it == str.begin()){if (tmp == '-'){sum *= -1;}else{break;}}else{sum = 0;break;}}count *= 10;}return sum;}
};
8-2:反转字符串:
题目链接
class Solution {
public:void reverseString(vector<char>& s) {reverse(s.begin(),s.end());vector<char>::iterator it = s.begin();while(it!=s.end()){cout<<*it;it++;}}
};
8-3:字符串中第一个唯一字符:
题目链接
1.定义一个26大小的数组去通过下标对应的方法记录每个字母出现的次数。
2.双for遍历,字符串和26这个数组。遍历字符串并且确定26数组中的值是不是1。
3.找到第一个只出现一次的数就返回:
4.时间复杂度为O(n)
class Solution {
public:int firstUniqChar(string s) {int arr[26] = { 0 };string::iterator it = s.begin();while (it != s.end()){int indx = (int)(*it - 97);arr[indx]++;it++;}string::iterator it1 = s.begin();int count = 0;while (it1 != s.end()){for (int i = 0; i < 26; i++){if (arr[(int)((*it1) - 97)] == 1){return count;}}count++;it1++;}return -1;}
};
8-4:字符串相加:
题目链接:
class Solution {
public:string addStrings(string num1, string num2){int end1 = num1.size()-1;int end2 = num2.size()-1; string s1;int indx=0;while(end1>=0 || end2>=0){int p1=0;int p2=0;//字符串转数值的操作:if(end1>=0){p1=(int)(num1[end1]-'0');}if(end2>=0){p2=(int)(num2[end2]-'0');}//记录和:int sum = p1+p2+indx;indx=sum/10;sum%=10;s1.push_back((sum+'0'));end1--;end2--;}if(indx>=1){s1.push_back((indx+'0'));}reverse(s1.begin(),s1.end());return s1;}
};