[cpp--->双端队列]

一、stack/queue底层实现

1.stack和queue模拟实现

stl中stack和queue的实现与其他数据结构不同,stack和queue都用是用的一个dequeue双端队列作为底层适配容器的基础上实现的.
stack.h

#pragma once
#include<iostream>
#include<vector>
using namespace std;
namespace kk
{
	template <class T, class container = vector<T>>
	class stack
	{
	public:
		void push(const T& val)
		{
			_con.push_back(val);
		}
		void pop()
		{
			_con.pop_back();
		}
		T& top()
		{
			return _con.back();
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		container _con;
	};
	void test_stack()
	{
		kk::stack<int> st;
		st.push(1);
		st.push(2);
		st.push(3);
		st.push(4);
		while (!st.empty())
		{
			cout << st.top() << " ";
			st.pop();
		}
		cout << endl;
	}
}

queue.h

#pragma once
#include<iostream>
#include<list>
using namespace std;
namespace xj
{
	template <class T, class container = list<T>>
	class queue
	{
	public:
		void push(const T& val)
		{
			_con.push_back(val);
		}
		void pop()
		{
			_con.pop_front();
		}
		T& front()
		{
			return _con.front();
		}
		T& back()
		{
			return _con.back();
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		container _con;
	};
	void test_queue()
	{
		xj::queue<int> q;
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);
		while (!q.empty())
		{
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;
	}
}

2.dequeue实现思想

dequeue是一个柔和了list和vector的一些优点的新容器;同时支持list和vector的所有功能;dequeue的底层实现又是用vector作为适配器,有一个主存数组用来存储指针,指针指向固定大小的数组,地址从主存的中间位置开始是存储;

头插是从左边新开辟数组的尾部开始插入,尾插是从当前数组的尾部插入,头插头删,尾插尾删都不需要挪动数据,效率很高.

访问可用元素位置减去左边第一个数组的大小,然后除以固定数组的大小确定数组位置,然后在%固定数组的大小确定元素位置,所以也支持随机访问.

中间位置插入,因为固定大小的数组不能扩容,所以只能挪动数据;但是如果将固定大小的数组改为可变大小的数组,那么就不支持随机访问了.所以不能兼顾访问和中间插入的效率.
在这里插入图片描述

迭代器的位置需要用四个成员记录,固定数组的头,固定数组的尾,当前元素位置,当前数组位置;在一个数组中访问元素,只需要边用cur就可以,跨数组访问需要将数组位置更新至下一个数组,然后更新数组的头和尾.让cur指向数组第一个元素即可.
在这里插入图片描述

3.dequeue与vector和list优缺点总结

list优点:任意位置插入删除效率高,不需要扩容;缺点:不支持随机访问,.
vector优点:支持随机访问,尾插尾删效率高;缺点:头插和中间插入删除效率低.扩容代价高.
dequeue优点:支持随机访问但是没有vector效率高,尾插尾删效率高,扩容只需要拷贝指针即可,代价很低;缺点:中间插入删除效率低或者是不支持随机访问.

二、stack/queue实战应用

1.最小栈

用两个栈实现,一个栈正常出入栈,一个栈用来记录当前栈中的最最小值,如果最小栈是空则入栈,或者是val小于等于栈顶入栈,出栈时正常栈栈顶等于最小栈的栈顶则出栈,否则不出.最小栈的栈顶就是最小值.

class MinStack {
public:

    void push(int val) {
        _st.push(val);
        if(_minst.empty()||val<=_minst.top())
        {
            _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;
};

2.栈的弹出压入序列

如果栈顶==popi就出栈并更新popi位置,直到栈为空或者栈顶不等于popi,否则就入栈pushi并更新pushi的位置.

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        int pushi=0,popi=0;
        stack<int> st;
        while(pushi!=pushV.size())
        {
            st.push(pushV[pushi++]);
            while(!st.empty()&&st.top()==popV[popi])
            {
                st.pop();
                popi++;
            }
        }
        return st.empty();
    }
};

3.逆波兰表达式求值

用一个栈辅助,如果tokens中是数字就入栈,如果不是就将栈顶的两个元素按照右左的顺序出栈并记录,然后判断是什么运算符,根据运算符确定left和right进行什么运算,将运算结果存储在栈中.最后栈顶就是结果

扩展:中缀变后缀的实现原理:用一个栈和一个string辅助实现,如果字符串中是数字就放入string,如果是运算符,同时栈是空或者栈顶的运算符优先级高于或者等于字符串中的运算符就出栈运算符放入string中,否则就入栈字符串中的运算符.处理完一个更新字符串字符索引位置到下一个位置.
比较特殊的情况是有括号的时候,当遇到左括号就无脑入栈,括号内的运算符按照其那面的逻辑出入栈,遇到有括号就认为右括号优先级是最低的,将括号内的运算符全部出栈,如果有括号遇到左括号就抵消处理.

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        int left=0,right=0;
        stack<int> st;
       for(auto str:tokens)
       {
           //这里如果直接使用单个字符比较会将复数算进去,所以使用string的比较重载函数
           if(str=="+"||str=="-"||str=="*"||str=="/")
           {
               right=st.top();
               st.pop();
               left=st.top();
               st.pop();
               //Switch只支持整型比较,char也属于整型
               switch(str[0])
               {
                   case '+':
                   {
                       st.push(left+right);
                       break;
                   }
                   case '-':
                   {
                       st.push(left-right);
                       break;
                   }
                   case '*':
                   {
                       st.push(left*right);
                       break;
                   }
                   case '/':
                   {
                       st.push(left/right);
                       break;
                   }
                   default :
                    break;
               }
           }
           else
           {
               st.push(stoi(str));
           }
       }
       return st.top();
    }
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是用C++实现双端队列的代码和详细步骤: ```cpp #include <iostream> using namespace std; #define MAXSIZE 100 // 定义双端队列的最大长度 class Deque { private: int data[MAXSIZE]; // 双端队列的数据存储数组 int left; // 左指针 int right; // 右指针 public: Deque() { // 构造函数,初始化左右指针 left = 0; right = 0; } bool isEmpty() { // 判断队列是否为空 return left == right; } bool isFull() { // 判断队列是否已满 return (right + 1) % MAXSIZE == left; } void push_front(int x) { // 在队头插入元素 if (isFull()) { cout << "Deque is full!" << endl; return; } left = (left - 1 + MAXSIZE) % MAXSIZE; data[left] = x; } void push_back(int x) { // 在队尾插入元素 if (isFull()) { cout << "Deque is full!" << endl; return; } data[right] = x; right = (right + 1) % MAXSIZE; } void pop_front() { // 在队头删除元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return; } left = (left + 1) % MAXSIZE; } void pop_back() { // 在队尾删除元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return; } right = (right - 1 + MAXSIZE) % MAXSIZE; } int front() { // 返回队头元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return -1; } return data[left]; } int back() { // 返回队尾元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return -1; } return data[(right - 1 + MAXSIZE) % MAXSIZE]; } }; int main() { Deque dq; dq.push_front(1); dq.push_back(2); dq.push_front(3); dq.push_back(4); cout << dq.front() << endl; // 输出:3 cout << dq.back() << endl; // 输出:4 dq.pop_front(); dq.pop_back(); cout << dq.front() << endl; // 输出:1 cout << dq.back() << endl; // 输出:2 return 0; } ``` 步骤: 1. 定义一个常量MAXSIZE,表示双端队列的最大长度。 2. 定义一个类Deque,包含数据存储数组data和左右指针left、right。 3. 构造函数初始化左右指针。 4. 定义isEmpty()和isFull()函数,分别判断队列是否为空和已满。 5. 定义push_front()和push_back()函数,在队头和队尾插入元素。 6. 定义pop_front()和pop_back()函数,在队头和队尾删除元素。 7. 定义front()和back()函数,分别返回队头和队尾元素。 8. 在main函数中创建Deque对象dq,测试双端队列的各种操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值