C++标准库中提供了三个容器适配器:stack(栈)、queue(队列)和priority queue(优先队列)。这三种容器适配器提供了简单易用的接口,满足了编程中的特殊数据处理需求,本节将针对这三种容器适配器进行讲解。
stack
stack中的元素具有后进先出的特点。stack只能从一端插入、删除、读取元素,不允许一次插入或删除多个元素,且不支持迭代器操作。stack存储结构如图7-17所示。下面分别介绍stack的常见用法。
图7-17 stack存储结构
1.创建stack
创建stack主要有两种方式,分别如下所示。
(1)创建空的stack。
创建空的stack,用于存储基本数据类型的元素,示例代码如下所示:
stack<int> st;
(2)创建存储序列容器的stack。
创建存储序列容器的stack,stack的类型参数有两个,第一个类型参数为元素的数据类型,第二个类型参数为容器类型,示例代码如下所示:
vector<int> v = { 1,2,3 }; //创建vector容器v
stack<int,vector <int >> s(v); //创建stack容器适配器s,存储容器v
2.元素访问
stack除了具有vector容器相同功能的成员函数,如empty()、size()、emplace()和swap()函数,还提供以下操作函数,如表7-3所示。
表7-3 stack元素操作函数含义
下面通过案例演示stack的具体用法,
测试1:
实例代码:
#include <iostream>
#include <iomanip>
#include<vector>
#include<deque>
#include<list>
#include<array>
#include<forward_list>
#include <set>
#include <functional>
#include <map>
#include <stack>
using namespace std;
template <class T>
void print_and_clear(stack<T ,vector<T>> &v)
{
cout << "void print_and_clear(stack<T ,vector<T>> &v)" << endl;
cout << "v.size() = " << v.size() << endl;
while(!v.empty()){
cout << v.top() << " ";
v.pop();
}
cout << endl;
}
template <class T>
void init_stack(stack<T ,vector<T>> &s)
{
vector<T> v = {1,2,3};
typename vector<T>::iterator it;
it = v.begin();
while(it != v.end()){
s.push(*it);
it++;
}
s.push(4);
}
int main()
{
stack<int ,vector<int>> s1;
init_stack(s1);
cout << s1.size() << endl;
print_and_clear(s1);
s1.emplace(5);
print_and_clear(s1);
cout << "--end--" << endl;
return 0;
}
测试结果:
4
void print_and_clear(stack<T ,vector<T>> &v)
v.size() = 4
4 3 2 1
void print_and_clear(stack<T ,vector<T>> &v)
v.size() = 1
5
--end--
测试2:自定义类,
进阶实例,看懂基本上就学会一半了,不是自己写的还未必能看的懂,估计我自己1个小时以后就忘,除非重写一遍,而且也没啥耐心研究。
#include <iostream>
#include <iomanip>
#include<vector>
#include<deque>
#include<list>
#include<array>
#include<forward_list>
#include <set>
#include <functional>
#include <map>
#include <stack>
using namespace std;
template <class T,int len>
class myclass
{
public:
array<T,len> *arr;
myclass(array<T,len> &a){
cout << "myclass(array<T,len> &a)" << endl;
arr = new array<T,len>(a);
cout << "myclass init" <<endl;
}
~myclass(){
delete arr;
cout << "myclass delete" <<endl;
}
myclass& operator=(myclass &a){
cout << "myclass& operator=(myclass &a)" << endl;
array<T,len> *p;
p = new myclass<T,len>(a.arr);
return *p;
}
void show()
{
cout << "void show()" << endl;
typename array<T,len>::iterator it;
it = this->arr->begin();
while(it != this->arr->end()){
cout << hex << *it << " ";
it++;
}
cout << endl;
}
};
int main()
{
array<unsigned int,5> au = {0x89,0x65,0x12,0x31,0x03};
myclass<unsigned int,5> m(au);
vector<myclass<unsigned int,5>> v;
v.push_back(m);
cout << "v.size() = " << v.size() << endl;
v[0].show();
stack<myclass<unsigned int,5>,vector<myclass<unsigned int,5>>> s(v);
cout << "s.size() = " << s.size() << endl;
myclass<unsigned int,5> m2 = (myclass<unsigned int,5>)s.top();
m2.show();
cout << "--endl--" << endl;
return 0;
}
执行结果:这个myclass类的析构函数被凌迟的四次,构造函数只调用了一次,这坑有点大啊。看看热闹就行了。
myclass(array<T,len> &a)
myclass init
v.size() = 1
void show()
89 65 12 31 3
s.size() = 1
void show()
89 65 12 31 3
--endl--
myclass delete
myclass delete
myclass delete
myclass delete
queue
queue中的元素具有先进先出的特点,元素只能从一端使用push()函数进行插入,从另一端使用pop()函数进行删除。queue的存储结构如图7-19所示。queue也不允许一次插入或删除多个元素,且不支持迭代器操作。queue创建对象的方式与stack相同,并且其接口与stack大部分都相同。除了提供了与vector相同的接口,queue还提供两个自己特有的成员函数,如表7-4所示。
图7-19 queue的存储结构
表7-4 queue的操作函数含义
下面通过案例演示queue的用法:
实例代码:
#include <iostream>
#include <iomanip>
#include<vector>
#include<deque>
#include<list>
#include<array>
#include<forward_list>
#include <set>
#include <functional>
#include <map>
#include <stack>
#include <queue>
using namespace std;
template <class T>
void print(queue<T, list<T>> &q)
{
while(!q.empty()){
cout << q.front() << " ";
q.pop();
}
cout << endl;
}
int main()
{
list<int> l = {1,2,3};
queue<int, list<int>> q(l);
cout << q.front() << " " << q.back() << endl;
cout << q.size() << endl;
print(q);
cout << q.size() << endl;
q.push(4);
q.emplace(5);
cout << q.front() << " " << q.back() << endl;
print(q);
cout << "--endl--" << endl;
return 0;
}
测试结果:
1 3
3
1 2 3
0
4 5
4 5
--endl--
priority_queue
priority_queue中的元素可以按照自定义的方式进行动态排序。向priority_queue中插入或删除元素时,priority_queue会动态地调整,以保证元素有序。priority_queue的存储结构如图7-21所示。
图7-21 priority_queue的存储结构
priority_queue创建方式与queue相同,只是在创建priority_queue时,可以指定优先规则,即最后一个模板参数可以是一个函数对象,指定元素排序规则。创建priority_queue的示例代码如下:
priority_queue<int,vector<int>,greater<int>> pq;
priority_queue的接口与queue相同,使用比较简单。下面通过案例演示priority_queue的具体用法,
测试实例,其中有三个子测试:
#include <iostream>
#include <iomanip>
#include<vector>
#include<deque>
#include<list>
#include<array>
#include<forward_list>
#include <set>
#include <functional>
#include <map>
#include <stack>
#include <queue>
using namespace std;
template <class T>
void print(priority_queue<T> &q)
{
while(!q.empty()){
cout << q.top() << " ";
q.pop();
}
cout << endl;
}
template <class T>
void print(priority_queue<T,vector<T>,greater<T>> &q)
{
while(!q.empty()){
cout << q.top() << " ";
q.pop();
}
cout << endl;
}
void test_1()
{
list<int> l = {1,12,3,15,4};
priority_queue<int> q;
list<int>::iterator it = l.begin();
while(it != l.end()){
q.push(*it);
it++;
}
q.push(10);
cout << q.size() << endl;
print(q);
cout << q.size() << endl;
}
void test_2()
{
cout << endl;
priority_queue<int,vector<int>,greater<int>> q;
list<int> l = {1,12,3,15,4};
list<int>::iterator it = l.begin();
while(it != l.end()){
q.push(*it);
it++;
}
q.push(10);
cout << q.size() << endl;
print(q);
cout << q.size() << endl;
}
template <class T>
class MyCompare{
public:
bool operator()(T x,T y){
return x > y;
}
};
template <class T>
void print(priority_queue<T,vector<T>,MyCompare<int>> &q)
{
while(!q.empty()){
cout << q.top() << " ";
q.pop();
}
cout << endl;
}
void test_3()
{
cout << endl;
priority_queue<int,vector<int>,MyCompare<int>> q;
for(int n: {21,12,23,15,24}){
q.push(n);
}
q.push(19);
cout << q.size() << endl;
print(q);
cout << q.size() << endl;
}
int main()
{
test_1();
test_2();
test_3();
cout << "--endl--" << endl;
return 0;
}
测试结果:
6
15 12 10 4 3 1
0
6
1 3 4 10 12 15
0
6
12 15 19 21 23 24
0
--endl--