STL序列式容器
序列式容器,即以线性排列来存储某一制定类型的数据,该类容器并不会自动对存储元素按照值的大小进行排序。序列式容器大致包括array,vector, deque,list,forward_list等,除此之外,stack和queue本质上也属于序列容器,不过是在deque的基础上形成,故更习惯称他们为容器适配器。
array
array是C++11标准中新增的序列容器,在普通数组的基础上添加了一些成员函数和全局函数。array容器的大小是固定的,无法动态的扩展或收缩。
初始化array容器:
//array容器以类模板的形式定义在<array>头文件中,位于命名空间std中,使用该容器需要引入<array>头文件,并默认使用std命名空间
#include <array>
using namespace std;
//array<T,N>类模板中,T用以指明容器中的存储的具体数据类型,N用于指明容器的大小,需要注意的是N必须是常量。
//初始化操作
array<double,10> values;//各元素值不确定,不会默认初始化
array<double,10> values{};//容器元素被默认初始化为0
array<double,10> values{1.0,2.0};//剩余八个元素被默认初始化为 0.0
array容器中包含at()这种成员函数,使得操作元素比普通数组更安全。
用法示例:
#include <iostream>
#include <array>
using namespace std;
int main()
{
std::array<int,4> values{};
//初始化容器为{0,1,2,3}
for(int i = 0; i<values.size();i++){
values.at(i) = i;
}
//使用get()重载函数输出指定位置元素
cout<< get<3>(values)<<endl;
//cout<<values.at(3)<<endl;
//如果容器不为空,输出容器内所有元素
if(!values.empty()){
for(auto val = values.begin();val<values.end();val++){
cout<< *val <<" "<<endl;
}
}
//三种访问元素的方式
cout<< "values[0] is: "<< values[0]<<endl;
cout<< "values[1] is: "<< values.at(1)<<endl;
cout<< "values[2] is: "<< get<2>(values)<<endl;
return 0;
}
访问array容器内单个元素:
容器名[]:没有做边界检查(性能开销),使用越界的索引去访问或者存储元素不会被检测到
容器名.at(索引):可确定索引是否越界
vector
vector 实现的是一个动态数组,即可以进行元素的插入或者删除,动态占用内存空间。在尾部插入或者删除元素时间复杂度为O(1),在容器头部或者中部插入或删除元素时间复杂度为线性阶O(n).vector 容器以类模板vector
#include <iostream>
using namespace std;
//创建空的vector容器
vector<double> values;//空的vector容器
values.reserve(20);//设置容器内存分配,至少容纳20个元素,不影响已存储的元素也不会生成任何元素
//创建时指定初始值和元素个数
vector<int> primes{2,3,4,5};
//创建时指定元素个数,但初始值默认为0
vector<int> primes(20);
//创建时指定元素个数和初始值
vector<double> values(20,1.0);//20个元素的值均为1.0
//复制其他容器元素
vector<int> values1(10,1);
vector<int> values2(values1);
vector<int> values2(values.begin(),values.begin()+2);
vector一些成员函数的用法:
#include <iostream>
#include <vector>
using namespace std;
int main(){
//初始化一个空的vector 容器
vector<char> value;
//向value容器尾部添加s,t,l
value.push_back('s');
value.push_back('t');
value.push_back('l');
//调用size()成员函数输出容器的元素个数
printf("元素个数为:%d\n",value.size());
//使用迭代器遍历容器
for(auto it = value.begin();it!=value.end();it++){
cout<<*it<<" ";
}
cout << endl;
//向容器开头插入字符
value.insert(value.begin(),'r');
cout<<"首个元素为"<<value.at(0)<<endl;
return 0;
}
访问元素
1.容器名[索引]:未进行边界检测,可能发生越界访问的错误
容器名.at(索引):会进行边界检测
2.容器名.front():容器第一个元素的引用
容器名.back(): 容器最后一个元素的引用
3.容器名.data():首个元素的指针
添加元素
push_back() 和 emplace_back()
两者底层实现机制不同,push_back()向容器尾部添加元素时,首先会创建这个元素,然后再将元素拷贝或者移动到容器中;而emplace_back()实现时直接在容器尾部创建这个元素,省去拷贝和移动元素的过程。
插入元素
指定位置是指迭代器指定的位置
insert():指定位置之前插入一个或者多个元素
emplace():指定位置之前插入一个元素
删除元素
deque
双端队列容器,deque擅长在序列尾部增加或者删除元素(时间复杂度为O(1),不擅长在序列中间添加或删除元素,该容器可以根据需要修改自身的容量或大小。不同的是deque擅长在序列头部添加或者删除元素,时间复杂度也是O(1),deque容器中存储元素不能保证所有元素都存储在连续的内存空间中。
deque以模板类deque
// 创建空的deque容器,创建之后可以做添加或者删除元素的操作
deque<int> d;
// 创建一个具有n个元素的deque,默认为0
deque<int> d(10);
// 建一个具有n个元素的deque且指定初始值
deque<int> d(10,5);
// 可以通过拷贝原有deque容器创建新的deque容器
deque<int> d1(5);
deque<int> d2(d1);
用法示例:
#include <iostream>
#include <deque>
using namespace std;
int main()
{
//初始化一个空deque容器
deque<int> q;
//向d容器尾部依次添加1,2,3
d.push_back(1);
d.push_back(2);
d.push_back(3);
//向d容器头部直接添加0
d.push_front(0);
//调用size函数输出容器存储字符个数
cout<<"元素个数为"<<d.size()<<endl;
//使用迭代器遍历容器
for(auto it = d.begin();it<d.end();it++){
cout<<*it<<" ";
}
cout << endl;
return 0;
}
向deque容器添加元素时,deque会申请更多的内存空间,同时其包含的所有元素可能会被复制或者移动到新的内存地址,从而导致之前创建的迭代器失效。
访问元素时同样有容器名[索引] 和at的方法,其区别前已说明。同样的front()和back()两个成员函数分别返回容器第一个和最后一个元素的引用。但不存在data()成员函数,因为deque存储元素时并不会将元素存储在连续的内存空间中。
list
双向链表容器,list容器的元素分散存储在内存空间中,而非必须存储在一整块连续的内存空间。各个元素的顺序依靠指针维系,据此可以在序列已知的位置快速插入或者删除元素,但是访问元素需要遍历容器。
list容器以模板类list头文件中,如何创建list容器:
//创建空的list容器
list<int> values;
//创建一个包含n个元素的list容器
list<int> values(10);
//创建包含n个元素的容器并指定初始值
list<int> values(10,3);
//通过拷贝或者指定区域来创建新的容器
list<int> value1(10,4);
list<int> value2(value1);
list<int> value2(value1.begin()+2,value1.end()-1);
list容器的重点在于其迭代器为双向迭代器而不是随机访问迭代器,故不支持通过下标访问list容器内指定位置的元素,仅支持++p,p++,p--,--p,*p,p1==p2以及p1!=P2等运算符。
list在进行插入(insert),接合(splice)等操作时,都不会造成原有的list迭代器失效,甚至删除操作,只有指向被删除元素的迭代器失效。
splice()成员方法移除元素的方式是,将存储该元素的节点从list容器底层的链表中摘除,然后再链接到当前 list容器底层的链表中,这意味着使用splice()成员方法将x容器中的元素添加到当前容器的同时,该元素会从x容器中删除。
删除元素:
根据元素所在位置删除:earse()
根据元素的值删除:remove()
forward_list
单链表,效率高
容器适配器
容器适配器就是将不适用的序列式容器变得适用,通过封装某个序列式容器,并重新组合该容器中包含的成员函数,使其满足某些特定场景的需要。容器适配器的本质上还是容器,只不过此容器模板类的实现,利用了大量其他基础容器模板类中已经写好的成员函数。
STL提供三种容器适配器,包括stack栈适配器,queue队列适配器,以及priority_queue优先权队列适配器。
stack
stack栈适配器是一种单端开口的容器,该容器实际上模拟的是栈存储结构,stack 适配器的开头端通常称为栈顶,数据的存取只能在栈顶处操作。栈中存储的元素满足后进先出的准则。满足条件的基础容器有vector,deque,list,默认使用的基础容器是deque。
stack容器的创建:以模板类stack<T,Container = deque
#include <iostream>
#include <stack>
using namespace std;
//创建不包含元素的stack适配器
stack<int> values;
//定义一个使用list基础容器的stack 适配器
stack<int,list<int>> values;
//使用基础容器初始化
list<int> values{1,2,3};
stack<int,list<int>> my_stack(values);//此时栈顶元素为3,同时stack第二个模板参数必须显式指定为list<int>,和存储类型保持一致,否则使用默认的deque容器将无法用list容器去初始化stack适配器
//用一个stack适配器初始化另一个stack适配器,需要它们存储的元素类型以及底层采用的基础容器类型相同
list<int> values{1,2,3};
stack<int,list<int>> mystack1(values);
stack<int,list<int>> mystack2(mystack1);
//stack<int,list<int>> mysatck2=mystack1;
部分成员函数用法示例
#include <iostream>
#include <stack>
#include <list>
using namespace std;
int main()
{
//构建stack容器适配器
list<int> values{1,2,3};
stack<int,list<int>> mystack(values);
//查看mystack里面存储元素的个数
cout<<"size of mystack"<<mystack.size()<<endl;
//将mystack中存储的元素依次弹栈,直到其为空
while(!mystack.empty()){
cout<<mystack.top()<<endl;
mystack.pop();
}
return 0;
}
queue
queue容器适配器有两个开口,一个用来专门输入数据,一个用来专门输出数据。queue成为队列适配器,具有先进先出的特点。
queue容器适配器以模板类queue<T,Container=deque
queue的创建
#include<iostream>
#incude<queue>
using namespace std;
//创建空的queue容器适配器
queue<int> values;
//手动指定基础容器的类型,存储的数据类型必须和queue容器适配器存储的元素类型数据一致。queue容器适配器底层容器可以选择deque和list
queue<int,list<int>> values;
//用基础容器初始化queue容器适配器
deque<int> values{1,2,3};
queue<int> myqueue(values);
//用一个queue容器适配器初始化另一个容器适配器
deque<int> values{1,2,3};
queue<int> myqueue1(values);
queue<int> myqueue2(myqueue1);
用法示例
#include <iostream>
#include <queue>
#include <list>
using namespace std;
int main()
{
//构建 queue 容器适配器
std::deque<int> values{ 1,2,3 };
std::queue<int> my_queue(values);//{1,2,3}
//查看 my_queue 存储元素的个数
cout << "size of my_queue: " << my_queue.size() << endl;
//访问 my_queue 中的元素
while (!my_queue.empty())
{
cout << my_queue.front() << endl;
//访问过的元素出队列
my_queue.pop();
}
return 0;
}
标签:容器,deque,适配器,元素,list,values,序列
From: https://www.cnblogs.com/perngfey-note/p/18104841