stack
stack是没有迭代器的,而STL要求每一种容器都必须内置一个迭代器,因此stack不是一种容器。 栈是一种先进后出的数据结构,一个栈的插入、删除或取值都只能在栈顶实现,在元素不弹出的前提下不能够遍历内部所有的元素。
根据栈的性质,栈顶元素必须是最后一个进入的元素,根据这点,我们可以很容易得出一个结论:任何提供末端插入push_back
、删除pop_back
、访问back
都能够被stack容器封装与修饰, 封装是指通过stack对象,不能直接访问被封装的底层容器,而修饰是指stack在对底层容器做封装时还提供了必要的接口,以满足用户的需要。 我们将被适配器封装的底层容器称为基础容器
适配器能够对原始事物进行一次封装与修饰,并提供另一种接口,该接口能够更好地满足用户的需求,具有一定的专一性。
在之前学过的顺序容器中,只要能够提供末端的插入、删除和访问操作,都可以作为stack适配器的基础容器,所以vector
、list
、deque
都可以作为stack的基础容器, stack默认的基础容器是deque
、
对于stack,我们通常需要提供的接口函数如下:
- 获取栈内当前元素的个数
size_type size();
- 获取栈顶元素
T top();
- 入栈
void push(const T &t);
- 出栈
void pop();
- 判断是否为空栈
bool empty();
如果想使用STL定义的容器适配器stack,需要引用stack头文件#include<stack>
stack的源码👇
- 底层是deque
#include<iostream>
#include<deque>
using namespace std;
- stack适配器的定义
template<class T,class Sequence=deque<T> >
class stack
{
friend bool operator==(const stack&,const stack&);//friend函数是全局函数,不受private的限制
friend bool operator<(const stack&,const stack&);//类内声明,类外定义,定义是不加friend
public:
typedef typename Sequence::value_type value_type;//typename类型声明,元素类型
typedef typename Sequence::size_type size_type;//大小类型
typedef typename Sequence::reference reference;//引用声明
typedef typename Sequence::const_reference const_reference;//常引用声明
protected:
Sequence c;//内部维护的容器,默认deque
public:
bool empty()const;//是否为空
size_type size()const;//大小
reference top();//取顶部元素
const_reference top()const;
void push(const value_type &x);//压栈
void pop();//出栈
};
- 各个函数接口的类外实现
template<class T,class Sequence>
bool operator==(const stack<T,Sequence> &x, const stack<T,Sequence> &y)//判断两个适配器是否相等
{
return x.c==y.c;
}
template<class T,class Sequence>
bool operator<(const stack<T,Sequence>& x,const stack<T,Sequence>& y)//判断适配器x是否小于适配器y
{
return x.c<y.c;
}
template<class T,class Sequence>
bool stack<T,Sequence>::empty()const//常成员函数类外定义需要加const关键字
{
return c.empty();
}
template<class T,class Sequence>//类外无需加默认形参
//如果写成size_type stack<T,Sequence>::size()const是错误的,因为size_type是在类内定义的,且typename最好也加上
typename stack<T,Sequence>::size_type stack<T,Sequence>::size()const
{
return c.size();
}
template<class T,class Sequence>
typename stack<T,Sequence>::reference stack<T,Sequence>::top()//底层实现是返回最后一个容器的元素
{
return c.back();
}
template<class T,class Sequence>
typename stack<T,Sequence>::const_reference stack<T,Sequence>::top()const//top函数的重载
{
return c.pop_back();
}
template<class T,class Sequence>
void stack<T,Sequence>::push(const value_type & x)//底层实现是向基础容器的尾部添加元素
{
c.push_back(x);
}
template<class T,class Sequence>
void stack<T,Sequence>::pop()//底层实现是将基础容器的尾部元素弹出
{
c.pop_back();
}
queue
queue内部依旧没有迭代器,能实现queue功能的容器都可以作为底层容器以封装修饰,本质上是适配器
队列的特点是先进先出,从队尾插入队首弹出,因此需要有pop_front
,所以vector
容器不适合作为底层容器,而是deque
、list
适合,默认是deque
queue所提供的操作如下:
(1)获取当前队列中元素的个数。size_type size()
(2)获取队首元素(不弹出)T & front()
(3)获取队尾部元素(不弹出)T & back()
(4)入队操作 void push(const T &t)
(5)出队操作 void pop()
(6)判断队列是否为空 bool empty()
同样用queue需要#include<queue>
实现源码👇
- deque为底层容器
#include<iostream>
#include<deque>
using namespace std;
- queue的定义
#include<iostream>
#include<deque>
using namespace std;
/****************queque的定义*************/
template<class T,class Sequence=deque<T> >
class queue
{
friend bool operator==(const queue& x,const queue& y);
friend bool operator<(const queue&x,const queue& y);
/****************容器适配器queue公有属性*********************/
public:
typedef typename Sequence::value_type value_type;//容器元素类型
typedef typename Sequence::size_type size_type;//大小类型
typedef typename Sequence::reference reference;//引用类型
typedef typename Sequence::const_reference const_reference;//常引用类型
protected:
Sequence c;//基础容器
/*************queue的常用操作****************/
public:
bool empty()const;//判断是否为空
size_type size()const;//元素个数
reference front();//获取队首元素
const_reference front()const;
reference back();//获取队尾元素
const_reference back()const ;
void push(const value_type& x);//进队列
void pop();//出队操作
};
- queue类外实现
template<class T,class Seq>
bool queue<T,Seq>::empty()const//判断队列是否为空队列,const在类外实现的时候也不能省
{
return c.empty();
}
template<class T,class Seq>
typename queue<T,Seq>::size_type queue<T,Seq>::size()const//返回队列内元素的个数
{
return c.size();
}
template<class T,class Seq>
typename queue<T,Seq>::reference queue<T,Seq>::front()//获取队首元素
{
return c.front();
}
template<class T,class Seq>
typename queue<T,Seq>::const_reference queue<T,Seq>::front()const//返回队首元素的常引用
{
return c.front();
}
template<class T,class Seq>
typename queue<T,Seq>::reference queue<T,Seq>::back()//取队尾元素的引用
{
return c.back();
}
template<class T,class Seq>
typename queue<T,Seq>::const_reference queue<T,Seq>::back()const//取队尾元素的引用
{
return c.back();
}
template<class T,class Seq>
void queue<T,Seq>::push(const value_type& t)//压队列
{
c.push_back(t);
}
template<class T,class Seq>
void queue<T,Seq>::pop()//出队列
{
c.pop_front();
}
- 测试代码
int main()
{
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
while(!q.empty())
{
cout<<"size="<<q.size()<<" ";
cout<<q.front()<<endl;
q.pop();
}
return 0;
}