C++栈和队列

1. OJ题

232. 用栈实现队列

cpp 复制代码
class MyQueue {
public:
    MyQueue() {
        
    }
    
    void push(int x) {
        pushst.push(x);
    }
    
    int pop() {
        if(popst.empty()){
            while(!pushst.empty()){
                int x=pushst.top();
                pushst.pop();
                popst.push(x);
            }
        }
        int x=popst.top();
        popst.pop();
        return x;
    }
    
    int peek() {
        if(popst.empty()){
            while(!pushst.empty()){
                int x=pushst.top();
                pushst.pop();
                popst.push(x);
            }
        }
        return popst.top();
    }
    
    bool empty() {
        return popst.empty()&&pushst.empty();
    }
private:
    stack<int> pushst;
    stack<int> popst;

};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

225. 用队列实现栈

cpp 复制代码
class MyStack {
public:
    MyStack() {
        
    }
    
    void push(int x) {
        pushq.push(x);
    }
    
    int pop() {
        if(pushq.empty()){
            while(popq.size()>1){
            int x=popq.front();
            popq.pop();
            pushq.push(x);
            }
            int x=popq.front();
            popq.pop();
            pushq.push(x);
        }
        while(pushq.size()>1){
            int x=pushq.front();
            pushq.pop();
            popq.push(x);
        }
        int x=pushq.front();
        pushq.pop();
        return x;
    }
    
    int top() {
        if(!pushq.empty())
            return pushq.back();
        return popq.back();
    }
    
    bool empty() {
        return pushq.empty()&&popq.empty();
    }
private:
    queue<int> pushq;
    queue<int> popq;
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

JZ31 栈的压入、弹出序列

cpp 复制代码
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        stack<int> st;
        int pushi=0,popi=0;
        while(pushi<pushV.size()){
            st.push(pushV[pushi++]);

            while(!st.empty() && st.top()==popV[popi]){
                st.pop();
                popi++;
            }
        }
        return popi==popV.size();
        //return st.empty();
    }
};

155. 最小栈

cpp 复制代码
class MinStack {
public:
    MinStack() {//因为成员变量都会走初始化列表,如果是内置类型不做处理,自定义类型走默认构造
    }
    //如果不写默认构造,系统自动生成,和上面逻辑一样
    
    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;
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

102. 二叉树的层序遍历

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        vector<int> v;
        queue<TreeNode*> q;
        size_t levelsize=0;
        if(root){
            q.push(root);
            levelsize=1;
        }
        while(!q.empty()){
            
            for(size_t i=0;i<levelsize;i++){
                TreeNode* front = q.front();
                q.pop();
                v.push_back(front->val);
                if(front->left)
                    q.push(front->left);
                if(front->right)
                    q.push(front->right);
            }
            
            vv.push_back(v);
            v.clear();
            levelsize=q.size();
        }
        return vv;
    }
};

107. 二叉树的层序遍历 II

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> vv;
        vector<int> v;
        queue<TreeNode*> q;
        size_t levelsize=0;
        if(root){
            q.push(root);
            levelsize=1;
        }
        while(!q.empty()){
            
            for(size_t i=0;i<levelsize;i++){
                TreeNode* front = q.front();
                q.pop();
                v.push_back(front->val);
                if(front->left)
                    q.push(front->left);
                if(front->right)
                    q.push(front->right);
            }
            
            vv.push_back(v);
            v.clear();
            levelsize=q.size();
        }
        reverse(vv.begin(),vv.end());//调用vector库里的swap对两个vector进行交换,本质是交换二者的三个指针,开销不大
        return vv;
    }
};

150. 逆波兰表达式求值

cpp 复制代码
class Solution {
public:
    int evalRPN(vector<string>& tokens) {//传参传的是string对象数组,因为像+-*/都是一个字符,但-3,一个字符就存不下,就需要放在字符串中,所以就都放在了字符串中,tokens存的是一个又一个常量字符串;如果直接存在一个字符串,操作符和操作数需要我们进行拆分,很麻烦
        stack<int> st;
        for(auto& str: tokens){
            if(str=="+"||str=="-"||str=="*"||str=="/"){//这个地方要进行字符串的比较,如果只比较第一个字符,就可能把负数的符号判成减号
                int right=st.top();
                st.pop();
                int left=st.top();
                st.pop();
                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;
                }
            }
            else{

                st.push(stoi(str));
            }
        }
        return st.top();
    }
};

逆波兰表达式也就是后缀表达式,

那么后缀表达式如何运算呢?我们在

2. 模拟实现

cpp 复制代码
#pragma once
namespace diy {
	//栈
	template<class T,class Container = vector<T>>
	class stack {
	public:
		T& top() {
			return _con.back();
		}

		void pop() {
			_con.pop_back();
		}

		void push(const T& x) {
			_con.push_back(x);
		}

		size_t size() {
			return _con.size();
		}

		bool empty() {
			return _con.empty();
		}
	private:
		Container _con;
	};

	void test() {
		//stack<int, vector<int>> st;
		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;

		stack<int,list<int>> st1;
		st1.push(1);
		st1.push(2);
		st1.push(3);
		st1.push(4);

		while (!st1.empty()) {
			cout << st1.top() << " ";
			st1.pop();
		}
		cout << endl;
	}
}
cpp 复制代码
#pragma once
namespace diy {
	//队列
	template<class T, class Container>
	class queue {
	public:
		T& front() {
			return _con.front();
		}

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

		void pop() {
			_con.pop_front();
			//_con.erase(_con.begin()); 一般是链式队列,vector头删效率低,如果是vector作为容器,vector没有提供pop_front,要用迭代器
		}

		void push(const T& x) {
			_con.push_back(x);
		}

		size_t size() {
			return _con.size();
		}

		bool empty() {
			return _con.empty();
		}
	private:
		Container _con;
	};

	void test1() {
		queue<int, list<int>> q;
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);

		while (!q.empty()) {
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;
	}
}
cpp 复制代码
//测试代码
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#include "stack.h"
#include "queue.h"

//测试std下的栈
void test_stack_queue() {
	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;
	
	//测试std下的队列
	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;

	////测试std下的双端队列
	deque<int> dq;
	dq.push_back(1);
	dq.push_back(2);
	dq.push_back(3);
	dq.push_back(4);
	dq.push_back(5);
	dq.push_back(6);

	for (size_t i = 0; i < dq.size(); i++) {
		cout << dq[i] << " ";
	}
	cout << endl;
}

//测试双端队列的sort效率,和vector对比
void test_op() {
	srand(time(0));
	deque<int> dq1, dq2;
	vector<int> v;
	int N = 10000000;
	v.reserve(N);
	for (size_t i = 0; i < N; i++) {
		auto e = rand();
		dq1.push_back(e);
		dq2.push_back(e);
	}

	size_t begin1 = clock();
	for (auto& e : dq1) {
		v.push_back(e);
	}
	sort(v.begin(), v.end());
	size_t i = 0;
	for (auto& e : dq1) {
		e = v[i++];
	}
	size_t end1 = clock();

	size_t begin2 = clock();
	sort(dq2.begin(), dq2.end());
	size_t end2 = clock();

	cout << "vector copy sort: " << end1 - begin1 << endl;
	cout << "deque sort: " << end2 - begin2 << endl;
}

int main() {
	//test_stack_queue();
	//test_op();
	diy::test1();
	return 0;
}

3. 双端队列

栈和队列都是运用已有的容器来适配自己的需求,栈和队列的默认适配容器都是deque双端队列;

我们先来回顾一下,链表和vector

好似二者的优劣天生不能共容,但还真有一个可以共容的,双端队列,允许头插头删尾插尾删,重载[ ]运算符

我们来简单看一下,

双端队列和vector相比,[ ]不够极致,极大缓解头插头删以及扩容效率问题,和list相比CPU高速缓存效率不错,支持随机访问

牛刀小试

  1. 一个栈的输入顺序是a,b,c,d,e则下列序列中不可能是出栈顺序是( )
    A.e,d,a,c,b
    B.a,e,d,c,b
    C.b,c,d,a,e
    D.b,c,a,d,e

A

  1. 下列代码的运行结果是( )
    A.gstrin
    B.grtnsg
    C.srting
    D.stirng
cpp 复制代码
void main(){
    queue<char> Q;
    char x,y;
    x='n';y='g';
    Q.push(x);Q.push('i');Q.push(y);
    Q.pop();Q.push('r');Q.push('t');Q.push(x);
    Q.pop();Q.push('s');
    while(!Q.empty()){
		x = Q.front();
		Q.pop();
		cout<<x;
	};
	cout<<y;
}

B

  1. 下列代码的运行结果是( )
    A.gstrin
    B.string
    C.srting
    D.stirng
cpp 复制代码
void main(){
    stack<char> S;
    char x,y;
    x='n';y='g';
    S.push(x);S.push('i');S.push(y);
    S.pop();S.push('r');S.push('t');S.push(x);
    S.pop();S.push('s');
    while(!S.empty()){
		x = S.top();
		S.pop();
		cout<<x;
	};
	cout<<y;
}

B

  1. 以下是一个二叉树的遍历算法,queue是FIFO队列,请参考下面的二叉树,根节点是root,正确的输出是( )
    A.1376254
    B.1245367
    C.1234567
    D.1327654
cpp 复制代码
queue.push(root);
while(!queue.empty())
{
    node = queue.top();
    queue.pop();                             
    output(node->value)    //输出节点对应数字

     if(node->left)
         queue.push(node->left);
     if(node->right)
         queue.push(node->right);   
}

C

相关推荐
森G14 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
橘颂TA14 小时前
【测试】高效浏览器操作:基础功能与优化设置大全
c++·功能测试·职场和发展·测试·web测试
一只小小的芙厨14 小时前
寒假集训笔记·以点为对象的树形DP
c++·算法
艾莉丝努力练剑15 小时前
hixl vs NCCL:昇腾生态通信库的独特优势分析
运维·c++·人工智能·cann
我在人间贩卖青春15 小时前
C++之new和delete
c++·delete·new
Trouvaille ~15 小时前
TCP Socket编程实战(三):线程池优化与TCP编程最佳实践
linux·运维·服务器·网络·c++·网络协议·tcp/ip
June`15 小时前
高并发网络框架:Reactor模式深度解析
linux·服务器·c++
小镇敲码人15 小时前
剖析CANN框架中Samples仓库:从示例到实战的AI开发指南
c++·人工智能·python·华为·acl·cann
刘琦沛在进步16 小时前
【C / C++】引用和函数重载的介绍
c语言·开发语言·c++