STL从广义上分为:容器,算法,迭代器
容器和算法之间通过迭代器进行无缝连接
STL六大组件分别是:容器、算法、迭代器、仿函数、适配器、空间适配器
容器:各种数据结构,如vector,list、deque、set、map等用来存放数据
算法:各种常用的算法,如sort、find等
迭代器:扮演了容器与算法之间的胶合剂
仿函数:行为类似函数,可以作为算法的某一种策略
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
空间适配器:负责空间的配置与管理
容器分为序列式容器和关联式容器
序列式容器:强调值的排序,序列式容器中的每一个元素均有固定的位置
关联式容器:二叉树结构,个元素之间没有严格的物理上的顺序关系
算法:解决问题的方法,有限的步骤,解决逻辑或数学上的问题
算法分为质变算法和非质变算法
质变算法:指质变过程中会更改区间内的元素的内容
非质变算法:在运算过程中不会更改区间内的元素内容
迭代器:提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方法
每个容器都有自己的专属迭代器
迭代器的使用类似于指针
int main() {
// v1 是一个元素类型为 int 的空 vector
vector<int> v1;
// 使用 v1 中所有元素初始化 v2
vector<int> v2(v1);
vector<int> v2 = v1;
// v3 中包含了 3 个值为 1 的元素
vector<int> v3(3, 1);
// v3 中包含了 4 个默认值初始化的元素
vector<int> v4(4);
//使用2, 3, 4初始化 v5
vector<int> v5{ 2, 3, 4 };
// 二维数组初始化
vector<vector<int>> v;
}
int main() {
vector<int> v;
// 如果 v 为空则返回 true,否则返回 false
v.empty();
// 返回 v 中元素的个数
v.size();
// 向 vector 的尾端添加值为 1 的元素。
// 注意:vector 不支持 push_front 操作。
v.push_back(1);
// 返回 v 中第 3 个位置上元素的引用,不能用下标操作添加元素
int n = v[3];
// 删除尾元素,返回void。vector同样 不支持 pop_front 操作。
// 若想在同时弹出元素的值,就必须在执行弹出之前保存它(可以使用 v.back())。
v.pop_back();
// 返回 v 中最后一个元素的引用
int m = v.back();
// 返回 v 中第一个元素的引用
int n = v.front();
vector<int> a{ 2, 0, 2, 2, 0, 3, 0, 9 };
a.resize(15); //修改容器大小,变长了用0填充,短了删除尾部元素
a.resize(15,100); // 变长用100填充
int n = a.capacity(); //返回容量大小
}
#include
#include
#include
#include
using namespace std;
void myPrint(int val) {
cout << val << endl;
}
int main() {
// 创建vector容器
vector<int> v;
// 向容器的末尾插入数值
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
// v.begin()指向第一个元素的迭代器
vector<int>::iterator itBegin = v.begin();
// v.end()指向最后一个元素的下一个元素的迭代器
vector<int>::iterator itEnd = v.end();
// 遍历v
while (itBegin != itEnd) {
cout << *itBegin << endl;
itBegin++;
}
// 遍历容器中的元素,并将元素作为参数传递给myPrint函数
for_each(v.begin(), v.end(), myPrint);
}
int main(void)
{
vector<int> a{ 1, 2, 3, };
auto it1 = a.begin(); // 返回一个迭代器类型,一般来说我们并不关心迭代器具体的数据类型
auto it2 = a.insert((it1 + 1), { 6, 7, 8 }); // 利用迭代器在第二个元素之前插入数据
}
int main(void)
{
vector<int> a{ 1, 2, 3, };
auto it1 = a.begin(); // 返回一个迭代器类型,一般来说我们并不关心迭代器具体的数据类型
auto it2 = a.erase(it1 + 1); // 删除元素 2,返回值为元素删除后被删除元素的当前位置的值
}
int main() {
// 创建vector容器
vector<vector<int>> v;
vector<int> v1;
vector<int> v2;
vector<int> v3;
vector<int> v4;
for (int i = 0; i < 4; i++) {
v1.push_back(10);
v2.push_back(20);
v3.push_back(30);
v4.push_back(40);
}
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++) {
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) {
cout << *vit << endl;
}
}
}
int main(void)
{
vector<int> a{ 2, 0, 2, 2, 0, 3, 0, 9 };
sort(a.begin(), a.end()); //排序
// 将重复的内容放在末尾,然后删除末尾元素
auto end_unique = unique(a.begin(), a.end());
a.erase(end_unique, a.end());
// 将送其中的元素进行翻转逆序
reverse(a.begin(), a.end());
// 找到最大值和最小值
auto it = max_element(a.begin(), a.end());
auto it = min_element(a.begin(), a.end());
for (int i : a)
cout << i << " ";
// 互换容器
vector<int> b;
a.swap(b); //将a和b进行互换
// 预留100个空间,预留的空间不可访问
a.reserve(100);
return 0;
}
int main() {
// 默认构造
string s1;
const char* str = "zhangsan";
// 通过char数组构造
string s2(str);
// 通过拷贝构造
string s3(s2);
// 初始化s4为10个a
string s4(10, 'a');
}
int main() {
string s1= "zhangsan";
string s2;
// 通过另一个字符串进行赋值
s2 = s1;
string s3;
// 赋值一个字符
s3 = 'a';
// 通过assign赋值
s3.assign("lisi");
// 将字符串lisishiren的前五个给s3赋值
s3.assign("lisishiren", 5);
// 将s2的值赋给s3
s3.assign(s2);
//给s3赋值5个x
s3.assign(5,'x');
}
int main() {
string s1= "zhangsan";
string s2 = "lisi";
// 将s2拼接到s1后面
s1 += s2;
s1.append(s2);
// 追加一个字符
s1 += 'c';
//追加一个字符串
s1 += "lisi";
s1.append("lpve");
// lpvedfad的前四个字符追加到s1
s1.append("lpvedfad",4);
// 截取lpvedfad的第4个字符开始的三个字符
s1.append("lpvedfad",4,3);
}
int main() {
string s1= "zhangsan";
string s2 = "lisi";
// 比较s1和s2的大小,n=0相等,n<0则s1小,n>0则s1大
int n = s1.compare(s2);
}
int main() {
string s1= "zhangsan";
// 获取第三个字符
s1[3];
s1.at(3);
// 修改第三个字符
s1[3]='x';
s1.at(3) = 'x';
}
int main() {
string s1= "zhangsan";
// 在位置1插入111
s1.insert(1, "111");
// 在位置1后面删除三个字符
s1.erase(1, 3);
}
int main() {
string s1= "zhangsan";
// 从第一个字符起截取三个字符
s1.substr(1, 3);
}
deque是一个双向队列,可以在队列的两端进行元素的插入和删除操作。
deque的特点是可以在队列的两端进行元素的操作,并且可以高效地在队列的任意位置进行元素的插入和删除操作
//deque的定义
deque<int>d1; //定义一个储存数据类型为int的双端队列d1
push_back()//在队列的尾部插入元素。
push_front()//在队列的头部插入元素。
pop_back()//删除队列尾部的元素。
pop_front()//删除队列头部的元素。
back()//返回队列尾部元素的引用。
front()//返回队列头部元素的引用。
clear()//清空队列中的所有元素。
empty()//判断队列是否为空。
size()//返回队列中元素的个数。
begin()//返回头位置的迭代器
end()//返回尾+1位置的迭代器
rbegin()//返回逆头位置的迭代器
rend()//返回逆尾-1位置的迭代器
insert()//在指定位置插入元素
erase()//在指定位置删除元素
list容器的底层数据结构为带头双向循环链表,这使得 list的元素可以存储在非相邻的内存中
list 在插入删除元素方面很有优势,在列表的任意位置进行插入和删除操作的时间复杂度为O(1)
不能直接通过位置(下标)来直接访问元素,想要访问list的某个元素,必须从list的一端(或已知位置)迭代到该元素
list还需要额外的存储空间来储存前一个元素和后一个元素的链接信息。
list优点
高效的插入和删除:由于std::list是基于带头双向循环链表实现的,插入和删除操作在任意位置都具有常数时间复杂度O(1),不需要移动其他元素。这使得std::list在需要频繁插入和删除元素的场景下非常高效。
稳定的迭代器:在std::list中进行插入和删除操作不会使得迭代器失效。这意味着在插入或删除元素后,仍然可以继续使用之前获取的迭代器进行遍历和操作。
list的缺点
低效的随机访问
占用额外内存
迭代器不支持指针算术:std::list的迭代器不支持指针算术运算,无法像指针那样直接进行加减操作,这限制了一些操作的灵活性
list<int> str_a;
list<int> lt2(10, 2); //构造含有10个2的int类型容器
list<int> lt3(lt2); //拷贝构造int类型的lt2容器的复制品
string s("hello world");
list<char> lt4(s.begin(), s.end()); //构造string对象某段迭代器区间的内容
int arr[] = { 1, 2, 3, 4, 5 };
int sz = sizeof(arr) / sizeof(int);
list<int> lt5(arr, arr + sz); //构造数组某段区间的复制品 ->本质是调用迭代器区间的构造函数
list<int> lt{ 1,2,3,4,5 }; // 直接使用花括号进行构造---C++11允许
int array[] = { 1,2,3,4,5,6,7,8 };
list<int> lt(array, array + sizeof(array) / sizeof(array[0]));
lt.begin(); //指向第一个元素的迭代器
lt.end(); //返回最后一个元素的下一个元素的迭代器
lt.rbegin(); //指向最后一个元素的迭代器
lt.rend(); //返回第一个元素的前一个元素的迭代器
list<int> mylist = { 1, 2 };
// 把mylist的大小设为5
mylist.resize(5);
// 把list大小设为4,不足部分填充5
mylist.resize(4, 5);
// 判空
mylist.empty();
mylist.clear(); //清空容器
mylist.front(); // 返回头元素
mylist.back(); // 返回尾元素
// 在list尾部插入一个元素8
mylist.push_back(8);
// 在list头部插入一个元素8
mylist.push_front(8);
// 删除mydeue尾部一个元素
mylist.pop_back();
// 删除mydeue头部一个元素
mylist.pop_front();
// it指向mylist的第二个元素
list<int>::iterator it = mylist.begin() + 1;
// 使用insert添加一个元素
list<int>::iterator itnew = mylist.insert(it, 10);
// 使用insert添加2个元素,value为20
mylist.insert(it, 2, 20);
list<int> list2{ 10, 20, 30 };
// it1指向list2的第一个元素
list<int>::iterator it1 = list2.begin();
// it2指向list2的最后一个元素后一个位置
list<int>::iterator it2 = list2.end();
// 使用insert在2之前添加[it1,it2)之间的元素
mylist.insert(it, it1, it2);
// it指向mylist的第二个元素
list<int>::iterator it = mylist.begin() + 1;
// 删除it指向的元素,即2,并返回一个迭代器指向2之后的元素
list<int>::iterator itnew = mylist.erase(it);
// it1指向mylist的第二个元素
list<int>::iterator it1 = mylist.begin() + 1;
// it2指向mylist的最后一个元素后一个位置
list<int>::iterator it2 = mylist.end();
// 删除[it1,it2)之间的元素,即删除2,3,4
mylist.erase(it1, it2);
// 交换list1和list2的元素
mylist.swap(list2);
// 将list2中所有元素插入到mylist的第一个位置
mylist.splice(mylist.begin(), list2);
// 将迭代器向后移动两个位置,指向第三个元素
std::advance(it, 2);
// 将list2的第一个元素(10)插入到mylist的第三个位置
mylist.splice(it, list2, list2.begin());
std::list<int> list5 = { 1, 2, 3, 4, 5 };
std::list<int> list6 = { 10, 20, 30 };
// 将list5中第二个到第四个元素移动到list6的末尾
auto first = list5.begin();
std::advance(first, 1);
auto last = list5.begin();
std::advance(last, 4);
list6.splice(list6.end(), list5, first, last);
mylist.remove(2);
bool isEven(int n) {
return n % 2 == 0;
}
mylist.remove_if(isEven);
mylist.unique(); //删除连续的重复元素
mylist.merge(list2); //将 list2 合并到 mylist 中,两个列表必须都是完成排序的
mylist.reverse(); //将该链表的所有元素的顺序反转