C++ (STL,顺序容器,关联容器,容器适配器)
STL
C++ 标准模板库(Standard Template Library,简称 STL)是一组泛型编程的模板类和函数,旨在提供常用的数据结构、算法和函数对象。STL 是 C++ 标准库的一部分,极大地提高了编程效率和代码的可重用性。STL 主要分为6个部分。
STL 的设计基于泛型编程的思想,通过使用模板,STL 提供了与类型无关的代码,从而实现了代码的高复用性和灵活性。
六大组件的基本应用
1.容器
顺序容器
顺序容器(Sequence Containers)是一类用于存储和管理具有顺序关系的元素的容器。这些容器允许在容器中的任 意位置插入和删除元素,并且可以通过迭代器访问元素。C++ STL中的顺序容器主要包括以下几种:
1. std::vector vector(向量)
特性:动态数组,能够存储具有相同类型的元素序列。
优点:支持随机访问,访问速度快(O(1)时间复杂度)。
缺点:在容器中间插入或删除元素时,可能需要移动大量元素,效率较低(O(n)时间复杂度)。
#include <iostream>#include <vector>using namespace std;int main(){// Create a vector v1 with 3 elements of default value 0vector<int> v1(3);// operator[]v1[0] = 10;// 在向量末尾处添加一个元素v1.push_back(20);v1.push_back(50);// 返回对向量中第一个元素的引用cout << "front: " << v1.front() << endl;// 返回对向量中最后一个元素的引用cout << "back: " << v1.back() << endl;// 将一个元素或多个元素插入到指定位置的向量中/*void insert(const_iterator position,size_type count,const Type& value);*/v1.insert(v1.begin()+2,2,30);cout << "----------------------------------" << endl;// 遍历vectorvector<int>::iterator iter;for(iter = v1.begin();iter!=v1.end();iter++){cout << *iter;if(iter!=v1.end()-1){cout << ",";}}cout << endl;// 删除向量末尾处的元素v1.pop_back();// 遍历vector通过atcout << "返回对向量中指定位置的元素的引用const_reference at(size_type position)
const;" << endl;for(int i=0;i<v1.size();i++){cout << i << " : " << v1.at(i);if(i!=v1.size()-1){cout << ",";}}cout << endl;// Create a vector containing stringvector<string> v2 = {"hello", "stl", "!"};vector<string>::iterator iter2;for(iter2 = v2.begin();iter2!=v2.end();iter2++){cout << *iter2;if(iter2!=v2.end()-1){cout << ",";}}cout << endl;return 0;}
2. std::deque(双端队列)
特性 :支持在两端快速插入和删除元素的动态数组。
优点 :支持随机访问,访问速度快(O(1)时间复杂度)。在两端插入和删除元素效率高(O(1)时间复杂 度)。
缺点 :在容器中间插入或删除元素时,效率较低(O(n)时间复杂度)。
deque的内存空间分布是小片连续,小片空间用链表相连。deque空间的重新分配比vector快,重新分配空间 后,原有的元素是不需要拷贝的
#include <iostream>#include <deque>using namespace std;int main(){deque<int> d{ 1, 2, 3, 4 };// operator[]d[0] = 10;// 在deque末尾添加元素d.push_back(20);d.push_back(50);// 在deque头部添加元素d.push_front(100);d.push_front(200);// 返回对deque中第一个元素的引用cout << "front: " << d.front() << endl;// 返回对deque中最后一个元素的引用cout << "back: " << d.back() << endl;cout << "----------------------------------" << endl;// 遍历dequedeque<int>::iterator iter;for(iter = d.begin();iter!=d.end();iter++){cout << *iter;if(iter!=d.end()-1){cout << ",";}}cout << endl;// 反向遍历dequecout << "--------------------------------" << endl;deque<int>::const_reverse_iterator iter2;for(iter2 = d.crbegin();iter2!=d.crend();iter2++){cout << *iter2;if(iter2!=d.crend()-1){cout << ",";}}cout << endl;// 删除deque末尾处的元素d.pop_back();// 删除deque头部的元素d.pop_front();// 遍历deque通过atcout << "返回对向量中指定位置的元素的引用const_reference at(size_type position)
const;" << endl;for(int i=0;i<d.size();i++){cout << i << " : " << d.at(i);if(i!=d.size()-1){cout << ",";}}cout << endl;return 0;}
3. std::list(双向链表)
特性 :双向链表,因此它的内存空间可以不连续,通过指针来进行数据的访问,支持在任何位置快速插入和删 除元素。
优点 :在任何位置插入和删除元素效率高(O(1)时间复杂度)。
缺点 : list没有了提供[]操作符的重载,不支持随机访问,访问元素需要从头节点开始遍历(O(n)时间复 杂度)。
#include <iostream>#include <list>using namespace std;
int main(){// Create a list containing integerslist<int> l = {7, 5, 16, 8};// Add an integer to the front of the listl.push_front(25);// Add an integer to the back of the listl.push_back(13);// 返回对list中第一个元素的引用cout << "front: " << l.front() << endl;// 返回对list中最后一个元素的引用cout << "back: " << l.back() << endl;cout << "----------------------------------" << endl;// 遍历listlist<int>::iterator iter;for(iter = l.begin();iter!=l.end();iter++){cout << *iter << " ";}cout << endl;// 反向遍历listcout << "--------------------------------" << endl;list<int>::const_reverse_iterator iter2;for(iter2 = l.crbegin();iter2!=l.crend();iter2++){cout << *iter2 << endl;}cout << "--------------------------------" << endl;// 删除list末尾处的元素l.pop_back();// 删除list头部的元素l.pop_front();for(iter = l.begin();iter!=l.end();iter++){cout << *iter << endl;}return 0;}
4. std::forward_list(单向链表):
特性 :单向链表,支持在任何位置快速插入和删除元素。
优点 :在任何位置插入和删除元素效率高(O(1)时间复杂度),内存占用较少。
缺点 :不支持随机访问,访问元素需要从头节点开始遍历(O(n)时间复杂度)。不支持反向遍历。
5. std::array(C++11引入):
特性 :固定大小的数组,大小在编译时确定,不支持动态调整大小
优点 :支持随机访问,访问速度快(O(1)时间复杂度)。性能通常优于std::vector,因为不需要动态内 存分配。
缺点 :大小固定,不能动态调整。
关联容器
set:集合,自动排序且不允许重复元素
multiset:允许重复元素的集合
map:键值对集合,键自动排序且不允许重复
multimap:允许重复的键值对的集合
set与multiset
set是一种关联性容器,底层使用红黑树实现,插入删除操作时仅仅移动指针即可,不涉及内存的移动和拷贝, 所以效率比较高。
set的含义是集合,它是一个有序的容器,里面的元素都是排序好的,支持插入,删除,查找等操作,就像一个 集合一样。所有的操作的都是严格在O(logn)时间之内完成,效率非常高。
set中的元素都是唯一的,而且默认情况下会对元素进行升序排列。
set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同
map、multimap
map容器提供一个键值对(key/value)容器 , map与multimap差别仅仅在于multiple允许一个键对应多个值。
map内部自建一棵红黑树(一种自平衡二叉树),这棵树具有数据自动排序的功能 , 所以在map内部所有的数据都是有序的,以二叉树的形式进行组织
无序容器
unordered_set: 基于哈希表的集合,不保证元素顺序且不允许重复元素
unordered_multiset:基于哈希表且允许重复元素的集合
unordered_map:基于哈希表的键值对集合,不保证元素顺序且不允许重复键
unordered_multimap:基于哈希表且允许重复键的键值对集合
容器适配器
stack:栈,通常基于 deque 或 vector 实现。
queue:队列,通常基于 deque 或 list 实现。
priority_queue:优先队列,通常基于 vector 实现,元素按优先级排序
适配器是标准库中的一个通用概念,容器,迭代器和函数都有适配器
C++中的适配器是一种设计模式
queue 队列 先进先出
只能从一段添加元素,从另一端取出元素
queue不是标准STL容器,却以标准的STL容器为基础,queue是在deque的基础上封装的
选择deque而不是vector是因为deque在删除元素时释放空间,同时在重新申请空间时无需拷贝所有元素