【C++初阶】stack和queue用法详解:常用接口、模拟实现与面试题(附完整代码)

🎬 博主名称键盘敲碎了雾霭
🔥 个人专栏 : 《C语言》《数据结构》 《C++》 《Matlab》 《Python》

⛺️指尖敲代码,雾霭皆可破


文章目录

  • 一、常用接口介绍
    • [1.1 stack](#1.1 stack)
    • [1.2 queue](#1.2 queue)
  • 二、常见面试题
    • [2.1 最小栈](#2.1 最小栈)
    • [2.2 栈的压入、弹出序列](#2.2 栈的压入、弹出序列)
    • [2.3 用栈实现队列](#2.3 用栈实现队列)
    • [2.4 用队列实现栈](#2.4 用队列实现栈)
    • [2.5 二叉树的层序遍历](#2.5 二叉树的层序遍历)
  • 三、模拟实现
    • [3.1 stack](#3.1 stack)
    • [3.2 queue](#3.2 queue)
  • 四、deque
    • [4.1 deque的引入](#4.1 deque的引入)
    • [4.2 底层结构](#4.2 底层结构)
    • [4.3 总结](#4.3 总结)
    • 五、优先级队列
    • [5.1 应用](#5.1 应用)
    • [5.2 模拟实现](#5.2 模拟实现)
  • 文章结语

一、常用接口介绍

1.1 stack

因为使用比较简单
详见文档https://legacy.cplusplus.com/reference/stack/stack/?kw=stack

1.2 queue

详见文档https://legacy.cplusplus.com/reference/queue/queue/?kw=queue

二、常见面试题

2.1 最小栈

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

代码实现

cpp 复制代码
class MinStack 
{
public:
    MinStack() 
    {
        
    }
    
    void push(int val) 
    {
        st1.push(val);
        if(st2.empty()||st1.top()<=st2.top())
        {
            st2.push(val);
        }
    }
    
    void pop() 
    {
        if(st1.top()==st2.top())
        {
            st2.pop();
        }
        st1.pop();
    }
    
    int top() 
    {
        return st1.top();
    }
    
    int getMin() 
    {
        return st2.top();
    }
private:
    stack<int> st1;
    stack<int> st2;
};

/**
 * 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();
 */

2.2 栈的压入、弹出序列

题目描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

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

2.3 用栈实现队列

题目描述:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作push、pop、peek、empty)

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

/**
 * 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();
 */

2.4 用队列实现栈

题目描述:请你仅使用两个队列实现一个后入先出作的栈,并支持普通栈的全部四种操作top、pop 和 empty)。

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

/**
 * 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();
 */

2.5 二叉树的层序遍历

题目描述:给你二叉树的根节点访问所有节点)。
root,返回其节点值的层序遍历。(即逐层地,从左到右)

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;
        queue<TreeNode*> q;
        int size=0;
        if(root)
        {
            q.push(root);
            size++;
        }
        while(!q.empty())
        {
            vector<int> v;
            while(size--)
            {
                TreeNode* front=q.front();
                v.push_back(front->val);
                q.pop();
                if(front->left)
                {
                    q.push(front->left);
                }
                if(front->right)
                {
                    q.push(front->right);
                }
            }
            size=q.size();
            vv.push_back(v);
        }
        return vv;
    }
};

三、模拟实现

由于stack和queue都是适配器,可以直接传容器类型进去,适配器是一种设计模式,该种模式是将一个类的接口转换成客户希望的另外一个接口。

3.1 stack

cpp 复制代码
#pragma once
#include<iostream>
#include<deque>
#include<vector>
#include<list>
namespace A
{
	template<class T,class Contain=deque<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		const T& top()const
		{
			return _con.back();
		}
		size_t size()const
		{
			return _con.size();
		}
		bool empty()const
		{
			return _con.empty();
		}

	private:
		Contain _con;
	};
}

3.2 queue

cpp 复制代码
#pragma once
namespace A
{
	template<class T,class Contain=deque<T>>
	class Queue
	{
	public:
		void push(const T&x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		const T& front()
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}
		size_t size()const
		{
			return _con.size();
		}
		bool empty()const
		{
			return _con.empty();
		}
	private:
		Contain _con;
	};
}

四、deque

4.1 deque的引入

deque相当于vector与list的缝合怪,两者的特点都有

deque(双端队列):是一种双开口的"连续"空间的数据结构 ,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高

4.2 底层结构

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组

4.3 总结

  • deque头插尾插效率很高,更甚于vector和list
  • 下标随机访问也还不错,相比vector略逊一筹
  • 中间插入删除效率很低,要挪动数据,是O(N)

五、优先级队列

具体文档:https://legacy.cplusplus.com/reference/queue/priority_queue/?kw=priority_queue

5.1 应用

cpp 复制代码
#include<queue>
#include<iostream>
using namespace std;
int main()
{
	priority_queue<int> qu;
	qu.push(1);
	qu.push(9);
	qu.push(5);
	qu.push(4);
	while (!qu.empty())
	{
		cout << qu.top() << " ";
		qu.pop();
	}
	cout << endl;
	return 0;
}

5.2 模拟实现

通过仿函数,可以模拟实现

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

template<class T>
class Great
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};
template<class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

namespace A
{
	template<class T,class Contain=vector<T>,class Compare=Less<T>>
	class priority_queue
	{
		Compare com;
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_con[parent] , _con[child]))
				{
					swap(_con[parent], _con[child]);
				}
				else
				{
					break;
				}
				child = parent;
				parent = (child - 1) / 2;
			}
		}
		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1< _con.size() && com(_con[child] , _con[child + 1]))
				{
					child++;
				}
				if ( com( _con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
				}
				else
				{
					break;
				}
				parent = child;
				child = parent * 2 + 1;
			}
		}

	public:
		void push(const T& x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}
		bool empty()const
		{
			return _con.empty();
		}
		const T& top()const
		{
			return _con[0];
		}
		size_t size()const
		{
			return _con.size();
		}
	private:
		Contain _con;
	};
}

文章结语

感谢你读到这里~我是「键盘敲碎了雾霭」,愿这篇文字帮你敲开了技术里的小迷雾 💻

如果内容对你有一点点帮助,不妨给个暖心三连吧👇

👍 点赞 | ❤️ 收藏 | ⭐ 关注

(听说三连的小伙伴,代码一次编译过,bug绕着走~)

你的支持,就是我继续敲碎技术雾霭的最大动力 🚀

🐶 小彩蛋:

复制代码
      /^ ^\
     / 0 0 \
     V\ Y /V
      / - \
    /    |
   V__) ||

摸一摸毛茸茸的小狗,赶走所有疲惫和bug~我们下篇见 ✨

相关推荐
承渊政道2 小时前
【递归、搜索与回溯算法】(递归问题拆解与经典模型实战大秘笈)
数据结构·c++·学习·算法·macos·dfs·bfs
少司府2 小时前
C++基础入门:类和对象(下)
开发语言·c++·类型转换·类和对象·友元
tankeven2 小时前
动态规划专题(05):区间动态规划实践(乘法游戏)
c++·算法·动态规划
小白学大数据2 小时前
Python 爬虫:拍卖网站列表页与详情页数据联动爬取
开发语言·爬虫·python
Highcharts.js2 小时前
在 Next.js App Router 中使用 Highcharts Stock(完整实战指南 )
开发语言·javascript·ecmascript
摇滚侠2 小时前
Groovy 中如何定义集合
java·开发语言·python
xiaoshuaishuai82 小时前
C# 实现Workstation相关功能
开发语言·windows·c#
游乐码2 小时前
c#Lsit排序
开发语言·c#
水饺编程2 小时前
第5章,[标签 Win32] :GDI 的基本图形
c语言·c++·windows·visual studio