STL
概述
STL,学名Standard Template Library,一般称它为标准模板库。
C++ 对模板(Template)支持得很好,STL 就是借助模板把常用的数据结构及其算法都实现了一遍,并且做到了数据结构和算法的分离。例如,vector 的底层为顺序表(数组),list 的底层为双向链表,deque 的底层为循环队列,set 的底层为红黑树,hash_set 的底层为哈希表。
从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map一大堆,STL也是算法和其他一些组件的集合。比如说中sort函数。
STL基本组成
STL从广义上讲分为三类:
1.容器(Container),是一种数据结构,如list,vector,和deques ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器;
2.迭代器(Iterator),提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符地方法的类对象;
3.算法(Algorithm),是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用;
string容器
用字符数组存放字符串容易发生数组越界的错误,而且往往难以察觉。因此,C++ 标准模板库设计了string 数据类型,专门用于字符串处理。
要使用string 对象,须包含头文件。
在用C++ 编程时,要优先考虑用string 对象来处理字符串,因为其用法比字符数组更简单,而且不容易出错。
初始化
string对象的初始化和普通类型变量的初始化基本相同,只是string作为类,还有类的一些特性:使用构造函数初始化。
string s1; //默认初始化,一个空字符串s1 string s2(s1); //s2是s1的副本 string s3 = s1; //等价于s3(s1),s3是s1的副本 string s4(“hello”); //s4是字面值”hello” string s5 = “hello”; //等价于上行代码 string s6(n,’a’); //把s6初始化为由连续的n个字符c组成的串 //调用string的构造函数生成一个临时的string类,再用临时的string类初始化。 string s7 = string(“hello”); string s8(string(“hello”));
输入输出
- 1.cin 输入
string s1; cin >> s1; //遇到空格终止 cout << s1 << endl;
- 2.getline读取整行
string s1; getline(cin,s1); cout << s1 << endl;
vs里面使用getline,须加上#include
比较大小
string可以直接使用> ,< == 等进行比较。
string s1 = “abc”,s2=”eda”; s1 > s2 s1 < s2 s1 == s2
链接
string可以使用+来直接链接。
string s1 = “hello”,s2 = “ world”; string s3 = s1 + s2;
获取字符
- 1.使用C++11新特性的for
string s1 = “abcdefg”; for (auto c:s1){ cout << c << “ “; }
- 2.使用运算符[] + size()函数
s1[0]; s1[1]; s1[2];
- 3.使用迭代器
string s1 = “hello world”; for(auto i=s1.begin();i!=s1.end();i++){ cout << *i << “ “; }
拷贝string对象
第一个将s1从下标pos开始拷贝到结尾。当pos>s1.size()时,为未定义行为;当pos=s1.size(),拷贝一个空字符。
第二个将s1从下标pos开始拷贝,拷贝len个字符。当pos>s1.size()时,为未定义行为;当pos=s2.size(),拷贝一个空字符。
string s(s1,pos); string s(s1,pos,len);
案例:
string s1("hello"); (1) string s2(s1, 1);//s2为”ello”,长度为4 (2) string s3(s1, 5);//s3为””,长度为0 (3) string s8(s1, 6);// 错误,未定义的行为,抛出异常 (4) string s4(s1, 1, 3);// s4为”ell”,长度为3 (5) string s5(s1, 1, 8);// 正确,s5为”ello”,长度为4 (6) string s6(s1, 5, 8);// s6为””,长度为0 (7) string s7(s1, 6, 1);// 错误,未定义的行为,抛出异常
substr函数
返回一个string对象,返回的对象包含s从pos下标开始的n个字符。pos和n均为可选参数。pos默认为下标0;n默认为s.size()-pos。
s.substr(pos,n);
案例:
string s ("value"); (1)string s2 = s.substr();//s2为”value”,大小为5 (2)string s3 = s.substr(2);//s3为”lue”,大小为3 (3)string s4 = s.substr(5);//s3为””,大小为0 (4)string s5 = s.substr(6);//错误,s5的大小为pos = 5,小于s.size() (5)string s6 = s.substr(1,2);// s6为”al”,大小为2 (6)string s7 = s.substr(1,7);// s7为”alue”,大小为4 (7)string s8 = s.substr(5,7);// s8为””,大小为0 (8)string s9 = s.substr(6,7);// 错误,s9的大小为pos = 5,小于s.size()
insert函数
- 1.iterator insert( iterator pos, CharT ch )
- 2.void insert( iterator pos, size_type count, CharT ch )
- 3.void insert( iterator pos, InputIt first, InputIt last )
- 4.插入初始化列表
案例:
string s1("value"); s1.insert(s1.begin(), 's');//执行后,s1为"svalue" s1.insert(s1.begin(), 1, 's');//执行后,s1为"ssvalue" s1.insert(s1.begin(), s1.begin(), ++s1.begin());//执行后,s1为"sssvalue" s1.insert(s1.end(), {'1','2'});//执行后,s1为"sssvalue12"
erase函数
//删除s从pos下标开始的n个字符,并返回删除后的s。当pos > s.size()时,报错 basic_string & erase(size_type pos=0, size_type n=npos); //删除s迭代器position位置的字符,并返回下一个字符的迭代器。 iterator erase(const_iterator position); //删除s迭代器[first,last)区间的字符,并返回last字符的迭代器。 iterator erase(const_iterator first, const_iterator last);
案例:
string s1("value"); string s2("value"); string s3("value"); string s4("value"); s1.erase();//执行后,s1为空 s2.erase(0,2); //执行后,s2为”lue” s2.erase(1); //执行后,s2为"l" s3.erase(s3.begin());//执行后,s3为”alue” s4.erase(s4.begin(),++s4.begin());//执行后,s4为”alue”
append函数
append是在string对象的末尾进行插入操作,这一点使用+运算符也能做到。
案例:
string s="C++"; s.append("program");//执行完后,s=”C++program”
replace函数
案例:
string s("i very love China!"); const char* cp1 = "truly"; const char* cp2 = "truly!!!"; string str1 = "really"; string str2 = "really!!!"; //1.将s从下标2开始删除4个字符,删除后在下标2处插入cp1 s.replace(2,4,cp1);//s=” i truly love China!” //2.将s从下标2开始删除5个字符,删除后在下标2插入cp2的前5个字符 s.replace(2, 5, cp2,5); //s=” i truly love China!” //3.将s从下标2开始删除5个字符,删除后在下标2插入str1 s.replace(2, 5, str1);//s=”i really love China!” //4.将s从下标2开始删除6个字符,删除后在下标2插入str2从下标0开始的6个字符 s.replace(2, 6, str2, 0, 6);//s=”i really love China!” //5.将s从下标2开始删除6个字符,删除后在下标2插入4个’*’字符 s.replace(2, 6, 4, '*');//s=”i **** love China!”
其他函数
- 1.find( )函数
string s = "1230,3210,220"; int start = 0; int index = s.find(',', start); //从下标为0开始查找,返回第一个','的下标,如果找不到返回-1
- 2.ispunct()函数:判断字符是否是标点符号用ispunct()
string s; cin >> s; for (auto each : s) { if (!ispunct(each)) { cout << each; } }
vector容器
c++ 中,vector 是一个十分有用的容器。它能够像容器一样存放各种类型的对象。也就是说,vector是一个能够存放任意类型的动态数组。
vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string 对象一样,标准库将负责管理与存储元素相关的内存。
把vector 称为容器,是因为它可以包含其他对象。一个容器中的所有对象都必须是同一种类型的。
头文件
使用vector须包含头文件vector
#include <vector>
声明与初始化
vector 可以声明各种类型,整型、字符型、字符串等等!
//整形数组 vector <int> vec = { 1,2,3,4,5}; //char型数组 vector <char> vec1 = {'h','e','l' ,'l' ,'o' }; //double vector<double> vec2 = {1.1,2.2,3.3};
利用构造函数初始化
vector():创建一个空vector vector(int nSize):创建一个vector,元素个数为nSize
vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
vector(const vector&):复制构造函数
vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
案例:
vector <int> vec(10);//定义一个含10个变量的整型数组vec,默认值都为0 vector <int> vec(10,2);//定义一个含10个变量的整型数组vec,默认值都为2 vector<int> vec(a);//其中a也是vector,把a整体赋值给vec vector<int> vec(a.begin(),a.begin+1);//把a的从开始到第二个赋值给vec
遍历函数
reference at(int pos):返回pos位置元素的引用
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
案例:
vector<int> v = { 1,2,3,4,5,6 }; cout << v.at(1) << endl; // 打印2 cout << v.front() << endl; //打印1 cout << v.back() << endl; // 打印6 for (auto i = v.begin(); i != v.end(); i++) { cout << *i << " "; } //输出1 2 3 4 5 6 cout << endl; for (auto i = v.rbegin(); i != v.rend(); i++) { cout << *i << " "; } //输出6 5 4 3 2 1
添加函数
//向量尾部增加一个元素X void push_back(const T& x); //向量中迭代器指向元素前增加一个元素x iterator insert(iteratorit,const T& x); //向量中迭代器指向元素前增加n个相同的元素x iterator insert(iterator it,int n,const T& x); //向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据 iterator insert(iterator it,const_iterator first,const_iterator last);
案例:
vector<int> v = { 1,2 }; vector<int> v2 = { 100,200 }; v.push_back(3); v.insert(v.begin(), 11); v.insert(v.begin() + 1, 3, 22); v.insert(v.begin(), v2.begin(), v2.end()); for (auto i = v.begin(); i != v.end(); i++) { cout << *i << " "; } //输出100 200 11 22 22 22 1 2 3
删除函数
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
案例:
vector<int> v = { 1,2,3,4,5,6 }; v.erase(v.begin()+1);//删除2 v.erase(v.begin() + 2, v.begin() + 4); //删除4 ,5 v.pop_back(); //删除最后一个元素 v.clear(); //清空所有元素 for (auto i = v.begin(); i != v.end(); i++) { cout << *i << " "; }
判断函数
bool empty() const:判断向量是否为空,若为空,则向量中无元素,返回1;反之,返回0
cout << v.empty() << endl;
大小函数
int size() const:返回向量中元素的个数
int capacity() const:返回当前向量所能容纳的最大元素值
int max_size() const:返回最大可允许的vector 元素数量值
案例:
vector<int> v = { 1,2,3,4,5,6 }; cout << v.size() << endl; //输出6 cout << v.capacity() << endl; //输出6 cout << v.max_size() << endl; //输出4611686018427387903
其他函数
1.void swap(vector&):交换两个同类型向量的数据
2.void assign(int n,const T& x):设置向量中前n个元素的值为x
3.void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素