C++ STL基础学习
标准模板库
- STL(Standard Template Library),是一些常用数据结构和算法的模板的集合,主要由 Alex Stepanov 主持开发,于 1998 年被加入 C++ 标准。
容器
- 容器(container)用于存放数据的类模板。
- 可变长数组、链表、平衡二叉树等 数据结构 在 STL 中都被实现为容器。
容器分类
-
顺序容器:vector 、deque(双端队列) 、 list(双向列表)
之所以被称为顺序容器,是因为元素在容器中的位置同元素的值无关,即容器不是排序的。
将元素插入容器时,指定在什么位置(尾部、头部或中间某处)插入,元素就会位于什么位置。
-
关联容器:set 、 multiset 、 map 、 multimap
关联容器内的元素是排序的。插入元素时,容器会按一定的排序规则将元素放到适当的位置上,因此插入元素时不能指定位置。
容器适配器
- STL 还在两类容器的基础上屏蔽一部分功能,突出或增加另一部分功能,实现了三种容器适配器:栈 stack、队列 queue、优先级队列 priority_queue。
成员函数
-
所有容器都有的两个成员函数
- int size() 返回容器对象中元素的个数
- bool empty() 判断容器是否为空
-
顺序容器和关联容器共有的成员函数
- begin() 返回指向容器中第一个元素的迭代器
- end() 返回指向容器中最后一个元素后面的位置的迭代器
- rbegin() 返回指向容器中最后一个元素的反向迭代器。
- rend() 返回指向容器中第一个元素前面的位置的反向迭代器。
- erase(...) 从容器中删除一个或几个元素。
- clear() 从容器中删除所有元素。
Ps:一个容器是空的,则 begin() 和 end() 的返回值相等,rbegin() 和 rend() 的返回值也相等。
-
顺序容器成员函数
- front():返回容器中第一个元素的引用。
- back():返回容器中最后一个元素的引用。
- push_back():在容器末尾增加新元素。
- pop_back():删除容器末尾的元素。
- insert(...):插入一个或多个元素。
-
关联容器成员函数
- find:查找某个值。
- lower_bound:查找某个下界。
- upper_bound:查找某个上界。
- equal_range:同时查找上界和下界。
- count:计算等于某个值的元素个数。
- insert:插人一个元素或一个区间。
迭代器的定义
正向迭代器 <容器类名>::iterator 迭代器名
反向迭代器 <容器类名>::reverse_iterator 迭代器名;
常量正向迭代器 <容器类名>::const_iterator 迭代器名
常量反向迭代器 <容器类名>::const_reverse_iterator 迭代器名;
容器适配器 stack、queue 和 priority_queue 没有迭代器。
迭代器 | 支持随机访问迭代器 | 支持双向迭代器 | 不支持迭代器 |
---|---|---|---|
容器 | vector、deque | list、set/multiset、map/multimap | stack、queue/priority queue |
迭代器都可以进行 ++
操作
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v; // 创建vector容器
for (int n = 0; n < 5; ++n)
// push_back成员函数在vector容器尾部添加一个元素
v.push_back(n);
// 定义正向迭代器 i
vector<int>::iterator i;
// 用迭代器遍历容器
for (i = v.begin(); i != v.end(); ++i)
cout << *i << " ";
cout << endl;
// 定义反向迭代器 j
for (vector<int>::reverse_iterator j = v.rbegin(); j != v.rend(); ++j)
cout << *j << " ";
return 0;
}
程序输出的结果:
0 1 2 3 4
4 3 2 1 0
常用辅助函数
- advance(p, n):使迭代器 p 向前或向后移动 n 个元素。
- distance(p, q):计算两个迭代器之间的距离,即迭代器 p 经过多少次 + + 操作后和迭代器 q 相等。如果调用时 p 已经指向 q 的后面,则这个函数会陷入死循环。
- iter_swap(p, q):用于交换两个迭代器 p、q 指向的值。
上述模板的使用需要包含< algorithm>头文件。
#include <list>
#include <iostream>
// 要使用操作迭代器的函数模板,需要包含此文件
#include <algorithm>
using namespace std;
int main()
{
int a[5] = {1, 3, 5, 7, 9};
// 将数组装进list容器
list<int> lst(a, a + 5);
// 是迭代器指向第一个元素
list<int>::iterator p = lst.begin();
// p向后移动两个元素,指向第三个元素
advance(p, 2);
cout << *p << endl; // 输出第三个元素5
// p向前移动一个元素,指向第二个元素
advance(p, -1);
cout << *p << endl; // 输出第二个元素3
// 是迭代器指向容器内最后一个元素后面的位置
list<int>::iterator q = lst.end();
// 是迭代器指向的位置前移一位
q--;
// 输出p元素与q元素的距离,即第三个元素和第五个元素的距离是3
cout << distance(p, q) << endl;
// 交换 p元素 和 q元素 的位置
iter_swap(p, q);
// 遍历输出容器内所有元素
for (p = lst.begin(); p != lst.end(); ++p)
cout << *p << " ";
return 0;
}
程序输出的结果
5 3 3 1 9 5 7 3
-
find:在容器中查找元素
该函数在头文件
和头文件 里都有,用法大致相同但不一样 find(first,last) 注意:这是一个左闭右开的区间,即 last 不在查找范围内
#include <vector>
#include <algorithm> //包含头文件
#include <iostream>
using namespace std;
int main()
{
int a[10] = {10, 20, 30, 40};
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// 此时v里放着4个元素:1,2,3,4
// 定义一个迭代器p
vector<int>::iterator p;
// 在v中查找元素 3
p = find(v.begin(), v.end(), 3);
// 若找不到,find返回 v.end()
if (p != v.end())
// 找到元素 3 就输出
cout << *p << endl;
p = find(v.begin(), v.end(), 9);
if (p == v.end())
// 如果没找到,打印NULL
cout << "NULL" << endl;
p = find(v.begin() + 1, v.end() - 1, 4);
// 在2,3这两个元素中查找4
cout << *p << endl;
// 为什么会输出4呢?因为返回的是end()
// 在数组a中所有元素中查找20
int *pp = find(a, a + 4, 20);
if (pp == a + 4)
cout << "NULL" << endl;
else
cout << *pp << endl;
return 0;
}
程序运行结果:
3 NULL 4 20
STL—vector
vector 容器在实现时,动态分配的存储空间一般都大于存放元素所需的空间。哪怕容器中只有一个元素,也会分配 32 个元素的存储空间。
这样做的好处是,在尾部添加一个新元素时不必重新分配空间,直接将新元素写入适当位置即可。在这种情况下,添加新元素的时间是常数。
当元素个数超过32个时,就会重新分配空间,并将原有内容copy到新空间。
vector容器的初始化:
vector
v; 空容器 vector
v(10); 初始化10个0 vector
v(3,6); 初始化3个6 vector
v{1,3,5,7,9}; 初始化1,3,5,7,9 vector<vector
> v; 嵌套形成二维数组
方法:
v.push_back(x); 追加一个元素x
v.erase(v.begin()); //删除第一个元素
v.erase(--v.end()); //删除最后一个元素
v.resize(10);//重置容器大小为10,不赋值默认为0
cout<<v.front(); //获取第一个元素
cout<<v[0];
cout<<*v.begin();
cout<<v.back(); //获取最后一个元素
cout<<v[v.size()-1];
cout<<*--v.end();
sort(v.begin(),v.end(),less
()); //从小到大排序,第三个参数默认可省略 sort(v.begin(),v.end(),greater
()); //从大到小排序,第三个参数不可省略
for(int i=0;i<v.size();i++) cout<<v[i];//for循环
for(vector
::iterator it=v.begin();it!=v.end();it++) cout<<*it;;//迭代器循环 for(auto it=v.begin();it!=v.end();it++) cout<<*it;//迭代器简化循环
for(auto x:v) cout<<x; (C++11新特性)
STL—deque
比之vector,它可以
dq.pop_front(); //删除头元素
dq.push_front(x); //增加头元素
STL—list
list
lst; //初始化
方法
lst.push_back(x); //尾部插入元素x
lst.push_front(x); //头部插入元素x
lst.emplace_front(x); //头部插入一个元素
lst.emplace_back(x); //尾部插入元素x
lst.insert(++li.begin(), x);//在第二个元素位置插入一个元素
lst.pop_front(); //删除第一个元素
lst.pop_back(); //删除最后一个元素
lst.clear(); //清空容器
算法 sort 需要随机访问迭代器的支持,list 不支持随机访问迭代器。
因此,list 容器引入了 sort 成员函数以完成排序。
lst.sort(); //从小到大排序
lst.sort(greater
()); //从大到小排列
STL—set/multiset
set | multiset |
---|---|
不允许有相同的元素 | 允许有相同的元素 |
set
s; multiset
::iterator s;
s.insert(x); //增加一个元素x
s.erase(x); //删除元素x
cout<<*s.lower_bound(x); //打印第一个大于或者等于x的元素
cout<<*s.upper_bound(x); //打印第一个大于x的元素
cout<<*s.find(x); //打印一个被查找到的元素
STL—map/multimap
有序,键值对(key-value),key具有唯一性
map<int,string> m;
m[1]="first";//增加元素
m[2]="second";
m.insert(pair<int,string>(3,"third"));//插入元素
m.insert(map<int,string>::value_type(4,"fourth"));
利用迭代器删除元素
map<int,string>::iterator it;
it = m.find(1);
m.erase(it);
清空map
m.erase(m.begin(),m.end());
STL—stack/queue/priority_queue
容器适配器是在顺序容器的基础上实现的,没有迭代器。
因此 STL 中的各种排序、查找、变序等算法都不适用于容器适配器。
- push 入栈一个元素
- pop 出栈一个元素,pop无返回值
- top 取栈顶元素
- size 查看元素个数
STL——string
string str("hello"); //str="hello "
string str(5,"A"); //str="AAAAA"
string str("12345",1,2); //str="23"
string str("hello");
str+="world"; //连接两段字符串
cout<<str;
string str;
s+=65; //ASCLL码转换
cout<<str;
string str;
getline(cin,str);//输入一行数据进入s
cout<<str;
string str("546123987")
sort(s.begin(),s.end()); //排序
str.erase(s.begin()); //删除第一个元素
str.erase(--s.end());
string str="456321789";
str=str.substr(1,3); //str="563" 截取子串