STL容器适配器stack和queue

STL容器适配器——stack、queue

什么是适配器? 适配器是一种设计模式(设计模式是一套被反复使用的。多数人知晓的、经过分类编目的、代码设计经验的总结),该模式是将一个类的接口转换成各户希望的另外一个接口。

stack和queue

  • STL容器适配器——stack、queue
  • 前言
  • 一、stack
    • 1.基本使用
    • 2.模拟实现
  • 二、queue
    • 1.基本使用
    • 2.模拟实现
    • 3.deque双端队列


前言

stack和queue是作为STL的容器适配器被实现的,容器适配器暨是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层。


一、stack

1.基本使用

先来看一下MSDN里面对stack的简单介绍STL容器适配器stack和queue_第1张图片
我们再来看一下stack简单的使用。

void main()
{
     
	stack<int> st;//容器适配器
	for (int i = 1; i <= 10; ++i)//将1到10顺序入栈
	{
     
		st.push(i);
	}
	cout << "st.size = " << st.size() << endl;
	while (!st.empty())//顺序出栈
	{
     
		int value = st.top();
		st.pop();
		cout << value << endl;
	}
	//无法通过迭代器访问
}	

给个题理解一下。
155.最小栈
题解:

class MinStack {
     
public:
    /** initialize your data structure here. */
    MinStack() 
    {
     }
    
    void push(int val) 
    {
     
        data_st.push(val);
        if(min_st.empty() || val<=min_st.top())
        min_st.push(val);
    }
    
    void pop() 
    {
     
        int val = data_st.top();
        data_st.pop();
        if(val == min_st.top())
            min_st.pop();
    }
    
    int top() 
    {
     
        return data_st.top();
    }
    
    int getMin() 
    {
     
        return min_st.top();
    }
private:
    stack<int> data_st;
    stack<int> min_st;
};

2.模拟实现

从栈的接口中可以看出,栈实际是一种特殊的vector,因此使用vector完全可以模拟实现stack。

namespace LJL
{
     
	template<class _Ty>
	class stack
	{
     
	public:
		stack()
		{
     }
		~stack()
		{
     }
	public:
		bool empty()const
		{
     
			return _C.empty();
		}
		size_t size()const
		{
     
			return _C.size();
		}
		_Ty& top()
		{
     
			return _C.back();
		}
		const _Ty& top()const
		{
     
			return _C.back();
		}
		void push(const _Ty &x)
		{
     
			_C.push_back(x);
		}
		void pop()
		{
     
			_C.pop_back();
		}
	private:
		vector<_Ty> _C;//若要使用list模拟只需要把vector改为list
	};
}

二、queue

1.基本使用

STL容器适配器stack和queue_第2张图片
注意这里的msdn有误,队列无top一说,队列的队头为front
代码演示:

void main()
{
     
	queue<int> q;//容器适配器
	for (int i = 1; i <= 10; ++i)//将1到10顺序入栈
	{
     
		q.push(i);
	}
	cout << "q.size = " << q.size() << endl;
	while (!q.empty())//顺序出栈
	{
     
		int value = q.front();
		q.pop();
		cout << value << endl;
	}
	//无法通过迭代器访问
}	

STL容器适配器stack和queue_第3张图片

2.模拟实现

因为queue的接口中存在头删和尾插,因此使用vector来封装的效率太低,故可以借助list来模拟实现。
代码如下:

#include 
namespace LJL
{
     
	template<class T>
	class queue
	{
     
	public:
		queue() {
     }
		void push(const T& x) {
      _c.push_back(x); }
		void pop() {
      _c.pop_front(); }
		T& back() {
      return _c.back(); }
		const T& back()const {
      return _c.back(); }
		T& front() {
      return _c.front(); }
		const T& front()const {
      return _c.front(); }
		size_t size()const {
      return _c.size(); }
		bool empty()const {
      return _c.empty(); }
	private:
		list<T> _c;
	};
}

在系统中stack和queue是用容器双端队列deque来模拟的。

#include 
namespace LJL
{
     
	template<class _Ty,class Cont=deque<_Ty>>
	class stack
	{
     
	public:
		stack()
		{
     }
		~stack()
		{
     }
	public:
		bool empty()const
		{
     
			return _C.empty();
		}
		size_t size()const
		{
     
			return _C.size();
		}
		_Ty& top()
		{
     
			return _C.back();
		}
		const _Ty& top()const
		{
     
			return _C.back();
		}
		void push(const _Ty &x)
		{
     
			_C.push_back(x);
		}
		void pop()
		{
     
			_C.pop_back();
		}
	private:
		Cont _C;
	};

	template<class _Ty, class Cont=deque<_Ty>>
	class queue
	{
     
	public:
		queue()
		{
     }
		~queue()
		{
     }
	public:
		bool empty()const
		{
     
			return _C.empty();
		}
		size_t size()const
		{
     
			return _C.size();
		}
		_Ty& front()
		{
     
			return _C.front();
		}
		_Ty& back()
		{
     
			return _C.back();
		}
		void pop()
		{
     
			_C.pop_front();
		}
		void push(const _Ty &x)
		{
     
			_C.push_back(x);
		}
	private:
		Cont _C;
	};
}

3.deque双端队列

是一种双开口的“连续”空间的数据结构(实际并不是连续的,而是由一段段连续的小空间拼接而成的,类似于一个动态的二维数组),可以再头尾两端进行插入和删除操作,且时间复杂度为O(1)而vector为O(n),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率较高,因为list不仅存储数据而且还需存储前后关系指针。
STL容器适配器stack和queue_第4张图片

相对于普通queue而言,deque既可以尾插也可以头插,既可以头删也可以尾删。而queue只能尾插和头删。
代码演示:

void main()
{
     
	deque<int> dq;
	for (int i = 1; i <= 3; ++i)
	{
     
		dq.push_back(i);//尾插
	}
	for (int i = 3; i >= 1; --i)
	{
     
		dq.push_front(i);//头插
	}
	for (const auto & e : dq)
	{
     
		cout << e << " ";
	}
	cout << endl;
	while (!dq.empty())
	{
     
		cout << dq.back() << endl;
		dq.pop_back();
	}
}

STL容器适配器stack和queue_第5张图片
deque的缺陷:
不适合遍历,因为在遍历时,deque的迭代器要频繁检测其是否移动到某段小空间的边界,导致效率低下,目前对于queue的应用主要为stack和queue的底层数据结构。


你可能感兴趣的:(c++,STL,容器适配器)