stack和queue

本文介绍了如何在C++中使用栈和队列,探讨了适配器模式的应用,特别是deque作为容器适配器的优势。通过实例展示了如何设计支持最小值查询的栈和验证逆波兰表达式的队列算法。同时,对比了deque与vector和list在不同场景下的性能特点。
摘要由CSDN通过智能技术生成

栈和队列不是容器而是容器适配器
在这里插入图片描述

栈和队列的使用

不支持迭代器,为了支持栈的先进后出,后进先出
在这里插入图片描述

void test_stack()
{
	stack<int> s;
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);
	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();//头删
	}
}

例题设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

链接

思路:我们利用c++的栈,设计出两个栈st和minST,st插入一个val,如果这时候minST为空,或者这个val小于等于minST.top(),minST就插入这个val,st删除的时候,如果被删除的val跟minST.top()一样,minST也pop.
在这里插入图片描述

class MinStack {
public:
    MinStack() {
    }//不需要我们自己写构造和析构,默认的就行了
    
    void push(int val) {
        st.push(val);
        if(minST.empty()||minST.top()>=val)
        {
           minST.push(val);
        }

    }
    
    void pop() {
     if(st.top()==minST.top())
     {
         minST.pop();
     }
     st.pop();
    }
    
    int top() {
     return st.top();
    }
    
    int getMin() {
      return minST.top();
    }
private:
    stack<int> st;
    stack<int> minST;
};

牛客网链接
拿入栈顺序去模拟出栈的顺序,如果可以模拟出来就行,不能就不行

  1. 入栈位置和出栈位置的值不相等,那么这个值需要先入,后面再出。
  2. 如果入栈位置的值和出栈位置的值相等,这个值还是入栈,持续出数据,直到栈为空或者栈顶的元素跟出栈序列的值不匹配。
class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        stack<int> st;
        size_t pushi=0,popi=0;
        while(pushi<pushV.size())
        {
            st.push(pushV[pushi]);
            pushi++;
            while(!st.empty()&&st.top()==popV[popi])
            {
                st.pop();
                popi++;
            }
        }
        if(st.empty())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};

例题
根据 逆波兰表示法,求表达式的值。

有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
在这里插入图片描述
链接

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(const auto& str: tokens)//把token每一个数据给赋值给str
        {
            if(str=="+"||str=="-"||str=="*"||str=="/")//如果是运算符就计算左右两个操作数
            {
                int right=st.top();//一定要分左右,不然乘除就有问题
                st.pop();
                int left=st.top();
                st.pop();
                switch(str[0])//str[0]就对应操作符
                {
                    case '+':
                      st.push(left+right);//再把数据push
                     break;
                    case '-':
                      st.push(left-right);
                      break;
                    case '*':
                    st.push(left*right);
                    break;
                    case '/':
                    st.push(left/right);
                    break;
                }
            }
            else
            {
                st.push(stoi(str));//stoi把字符串转化成整数
            }
        }
        return st.top();

    }
};

队列同样不支持迭代器,为了支持队列的先进先出,后进后出

队列和栈的实现

#pragma once
#include<vector>
#include<list>

namespace cl
{
	template<class T,class Container=deque<T>>
	class queue
	{
	public:
		bool empty()const
		{
			return _con.empty();
		}

		size_t size()const
		{
			return _con.size();
		}
		const T& front()const
		{
			return _con.front();
		}

		const T& back()const
		{
			return _con.back();
		}

		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
	private:
		Container _con;
	};
	
	//适配器模式
	template<class T,class Container>//r
	class stack
	{
	public:

		bool empty()const
		{
			return _con.empty();
		}

		size_t size()const
		{
			return _con.size();
		}
		const T& top()const
		{
			return _con.back();
		}

		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
	private:
		Container _con;
	};

	void test_stack()
	{
		stack<int,std::vector<int>> s;
		s.push(1);
		s.push(2);
		s.push(3);
		s.push(4);
		while (!s.empty())
		{
			cout << s.top() << " ";
			s.pop();
		}
		cout << endl;
	}
	void test_queue()
	{
		//queue<int> q;
		queue<int,list<int>> q;
		//queue<int, vector<int>> q;//会报错
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);
		while (!q.empty())//队列是先进先出
		{
			cout << q.front() << " ";//取队尾
			q.pop();
		}
		cout << endl;
	}
}

适配器模式

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

deque

deque是双端队列,融合vector和list的优点

vector优点:下标随机访问,尾插尾删效率高
缺点:扩容,不适合头插头删

list优点:按需申请释放空间,任意位置O(1)插入删除
缺点:不支持下标随机访问

deque:适合头尾的插入删除
如果没有deque,stack的实现用vector和list默认适配
queue用list默认适配
相比vector的优势:扩容代价不打,不需要拷贝数据,浪费空间不多
相比list的优势:cpu高速cache命中,其中不会频繁申请小块空间,申请和释放空间次数少,代价低

deque做为stack和queue是容器是非常合适的
deque适合头尾插入删除,但是中间插入删除,和随机访问效率都差强人意,所以高频访问还是vector,任意位置插入删除还是list

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值