STL(Standard Template Library)是C++的一套功能强大的 C++ 模板类和函数的集合,它提供了一系列通用的、可复用的算法和数据结构。
STL 的设计基于泛型编程,这意味着使用模板可以编写出独立于任何特定数据类型的代码。
STL 分为多个组件,包括容器(Containers)、迭代器(Iterators)、算法(Algorithms)、函数对象(Function Objects)和适配器(Adapters)等。
本节我们浅浅的介绍STL的容器部分,目前情况先学会如何使用,之后数据结构与C++语法的学习过程中逐渐思考如何模拟实现。
前言:字符串
1.字符串std::string
对C风格字符串的封装,也是容器类的“先驱”类,也可以称为“实验品”,但这只是相对而言。字符串类string本身功能还是非常强大的。
#include <iostream>
#include <string>
using namespace std;string str;//声明字符串变量
string str2="123";//初始化字符串变量string s1="hello";
string s2="stark";
string s3=s1+s2;//使用重载后的操作符 + 连接两个字符串
字符串类还提供了许多成员函数来操作字符串,以下是一些常用的成员函数:
size():返回字符串的长度
empty():检查字符串是否为空
substr():获取子字符串
find():查找子字符串在主字符串中的位置
replace():替换字符串中的某些字符
operator[]:通过索引访问字符串中的字符。(下标访问:使用时变量名相当于数组名)
一、数组容器
1.定长数组容器std::array
定长数组容器是C++标准库(STL)中的一个模板类,它定义在<array>头文件中。该模板类提供了一个固定大小的数组,其大小在编译时确定,并且不允许动态改变。与C语言的数组相比,具有更好的类型安全和内存管理特性。(C++11标准引入)
基本语法:
#include <array>std::array<T , N> arrat_name;
T是数组中元素的类型,N是数组的大小,必须是一个非负整数。
提供的接口:
如size()、at()、front()、back()等
2.动态数组容器std::vector
vector是变长数组,支持随机访问,不支持在任意位置插入,为了保证效率,元素的增删一般在末尾进行。这样保证了方法的时间复杂度为O(1)。在<vector>头文件中。
基本语法:
#include <vector>std::vector<T> vec_name;//声明一个T类型数组,长度动态变化
std::vector<T> vec_name[size];//声明一个T类型二维数组,第一维长size,第二维动态变化struct myType{...};
std::vector<myType> vec_name;//自定义结构体类型也可以存放在vector中
内置函数:
size():返回容器的实际长度(包含的元素个数)。O(1)
empty():返回一个bool值,表明vector是否为空。O(1)
clear():把vector清空
frond():返回容器第一个元素,等价于a[0]和*(a.begin())
back():返回容器最后一个元素,等价于a[a.size()-1]和*(a.end())
push_back():push_back(x)把元素x插入到vector的尾部
pop_back():删除vector的最后一个元素
二、队列容器
1.队列容器std::queue
队列是一种先进先出(FIFO, First In First Out)的数据结构,它允许在一端添加元素(称为队尾),并在另一端移除元素(称为队首)。队列是一种线性数据结构,它遵循以下规则:
1.元素只能从队尾添加。2.元素只能从队首移除。
基本语法:
#include <queue>// 声明队列
queue<T> q;
基本操作:
empty(); //检查队列是否为空。
size();//返回队列中的元素数量。front(); //返回队首元素的引用。
back(); //返回队尾元素的引用。push(); //在队尾添加一个元素。
pop(); //移除队首元素。
2.双端队列容器std::deque
C++ 容器类 <deque> | 菜鸟教程
3.优先队列容器std::priority_queue
C++ 容器类 <priority_queue> | 菜鸟教程
三、链表容器
1.双向链表容器std::list
list是一种将数据进行链式存储的数据结构,被称为链表。链表由一个存储数据元素的数据域和一个存储下一个结点地址的指针域组成
基本语法:
#include <list>list<T> lst;//默认构造,只声明一个存储T类型的链表容器
list(begin,end);//构造函数,利用迭代器实现区间赋值
list(n,elem);//构造函数,将n个elem赋值给本身
list(const list &list);//拷贝构造
list的赋值
函数原型
.list& operator=(const list& lst);//赋值运算符重载
.assign(begin,end);//利用迭代器实现区间赋值
.assign(n,elem);//将n个elem赋值给本身
.swap(lst);//将另一个lst与本身进行互换
list的数据获取
.front();//返回容器第一个元素
.back();//返回容器最后一个元素
list的大小操作
函数原型:
.size();//返回容器中有效元素个数
.empty();//判断容器是否为空
.resize(num);//重新指定容器长度
//若变长,扩容部分赋值为0;若变短,超出长度的元素被删除
.resize(num,elem);//重新指定容器长度
//若变长,扩容部分赋值为elem;若变短,超出长度的元素被删除
list的反转与排序
.reverse();//反转链表
.sort();//链表排序
//sort(lst1.begin(),lst1.end())//错误
//所有不支持随机访问迭代器的容器,不能使用标准算法
//但不支持随机访问迭代器的容器,内部会提供一些算法来弥补
list的插入/删除
.push_back(elem);//尾插
.push_front(elem);//头插
.pop_back();//尾删
.pop_front();//头删
.insert(pos,elem);//在迭代器pos处插入一个元素elem,并返回新数据的位置
.insert(pos,n,elem);//插入n个元素elem,无返回值
.insert(pos,begin,end);//在迭代器pos处插入begin,end区间(左闭右开)的数据,无返回值.clear();//清空容器
.erase(begin,end);//删除区间,返回下一个数据的位置
.erase(pos);//按位删除,返回下一个数据的位置
.remove(elem);//按值删除
2.单向链表容器std::forward_list
before_begin() //返回一个前向迭代器,其指向容器中第一个元素之前的位置。
begin() //返回一个前向迭代器,其指向容器中第一个元素的位置。
end() //返回一个前向迭代器,其指向容器中最后一个元素之后的位置。cbefore_begin()//和 before_begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。cbegin()//和begin()功能相同,只不过在其基础上增加了const属性,不能用于修改元素
cend() //和end()功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素empty() //判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。max_size() //返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。front() //返回第一个元素的引用。
assign() //用新元素替换容器中原有内容。
push_front() //在容器头部插入一个元素。emplace_front() //在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。pop_front() //删除容器头部的一个元素。emplace_after() //在指定位置之后插入一个新元素,并返回一个指向新元素的迭代器。和insert_after() 的功能相同,但效率更高。insert_after() //在指定位置之后插入一个新元素,并返回一个指向新元素的迭代器。
erase_after() //删除容器中某个指定位置或区域内的所有元素。
swap() //交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。
resize() //调整容器的大小。
clear() //删除容器存储的所有元素。splice_after() //将某个 forward_list 容器中指定位置或区域内的元素插入到另一个容器的指定位置之后。remove(val) //删除容器中所有等于 val 的元素。
remove_if() //删除容器中满足条件的元素。
unique() //删除容器中相邻的重复元素,只保留一个。merge() //合并两个事先已排好序的 forward_list 容器,并且合并之后的 forward_list 容器依然是有序的。sort() //通过更改容器中元素的位置,将它们进行排序。
reverse() //反转容器中元素的顺序。
四、栈容器
1.栈容器std::tack
<stack>
的底层容器可以是任何支持随机访问迭代器的序列容器,如vector
或deque
。
基本语法:
#include <stack>stack<T> s;
基本操作:
push();//在栈顶添加一个元素:入栈/压栈
pop();//移除栈顶元素:出栈
top();//返回栈顶元素的引用,但不移除:取栈顶值empty();//检查栈是否为空:判空
size();//返回栈中元素数量
五、映射容器
1.映射容器std::map
map容器是一个“键值对”key-val的映射,其内部实现是一颗以key为关键码的红黑树。map的key和value可以是任意类型,其中key的数据类型必须定义小于号运算符。
基本语法:
#include <map>map<T,T> m;//map<key_type,val_type> map_name;
//例如:
map<long long,bool>vis;
map<string,int> hash;
map<pair<int,int>,vector<int>> test;
常用内置函数:
size();empty();clear();begin();end();
insert();//参数为pair<key_type,val_type>;
例:m.insert({"666",666});
find(x);在映射容器中查找key为x的二元组。
operator[];//下标访问操作符重载
//m[key]返回key映射的val的值的引用,时间复杂度为O(logn);
//[]操作符是map最吸引人的地方。
map与unordered_map的区别:前者是红黑树,后者是哈希表;前者有序,后者无序
六、集合容器
头文件<set>主要包括set和multiset两个容器,分别是有序集合和有序多重集合。前者元素不能重复,后者可以包含若干个相等的元素。两者的底层都是一颗红黑树,支持的函数基本相同。
1.集合容器std::set
2.多重集合容器std::multiset
基本语法:
#include <set>std::set<T> set_name;
std::multiset<T> multiset_name;//以上为缺省型声明,即不明确排序方式--默认为升序
//以set为例:
std::set<T,less<T>>,将T类型的数据按照升序排列
std::set<T,greater<T>>,将T类型的数据按照降序排列
//由于需要对T类型进行排序,所以如果T类型为结构体类型,必须定义小于号
内置函数:
size()、empty()、clear();
insert():s.insert(x)把一个元素插入到集合s中,时间复杂度O(logn)。在set中由于是去重的,不会重复插入元素,当元素已经存在时,insert()对集合状态无影响。
find():s.find(x)在集合s中查找等于x的元素,并指向该元素的迭代器。不存在返回s.end()。时间复杂度为O(logn)
lower_bound():s.lower_bound(x)查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
upper_bound():查找大于x的元素中最小的一个,并返回指向该元素的迭代器。
count():s.count(x),返回集合s中等于x的元素个数,时间复杂度为O(k+logn),k为元素x的个数。
七、无序容器(C++11引入)
1.无序集合容器std::unordered_set
C++ 容器类 <unordered_set> | 菜鸟教程
2.无序映射容器std::unordered_map
C++ 容器类 <unordered_map> | 菜鸟教程
3.无序多重集合容器std::unordered_multiset
特点:无序,不去重。其余与unordered_set类似
4.无序多重映射容器std::unordered_multimap
特点:无序,不去重。其余与unordered_map类似
C++ 标准库 | 菜鸟教程 (runoob.com)
感谢大家!