本文章适用于了解过栈和队列结构的读者阅读,本文章代码使用c++实现!
目录
1.栈和队列的特点
栈和队列都是比较常见的数据结构
1.1: 栈的特点
栈的特点就是后插入的数据先出来,所谓后进先出
一个经典的例子就是手枪中的子弹,最后压入的子弹最先打出来
1.2: 队列的特点
先插入的数据先出来,先进先出
一个经典的例子就是排队
2.如何使用两个队列来模拟栈的各种操作?
假如面试官现在给你提供了两个完备的队列,你可以使用队列中的各种操作,如pop,push,front等。
最后能够实现队列中的pop,push,front等操作
本文使用c++ stl中的queue作为面试官提供的队列。
2.1分析结构
假设我们在栈中插入数据1 2 3,然后在删除3,再插入数据 4 5,最后依次弹出
那么我们得到到弹出序列应该为 3 5 4 2 1
如果使用两个队列来实现,第一次插入数据时,在第一个队列中插入数据即可
每当要弹出数据的时候,我们要删除的栈顶元素为这个队列的队尾元素,如下图
然后弹出栈顶的3(即队列队尾的3)
那么,我们如何操作呢? 由于队列是先进先出,可以将先进去的1,2插入到队列2中,如下图
每次将有数据的队列中的数据除了队尾的元素以外,都插入到另一个队列中即可
这样我们直接队列1中删除队首元素即可(此时只有一个元素)
每次插入新的数据的时候,我们在不为空的队列中插入数据即可。
如下图
此时弹出所有数据,将1 2 4 插入到队列1中,再删除 队列2的5即可.如下图
之后依次删除即可得到正确的结果
3.分析结束,代码实现
3.1整体框架
//利用两个队列实现栈
class MyStack
{
public:
MyStack()
{
queue<int> q1;
queue<int> q2;
}
//删除数据
void Pop()
{}
//插入数据
void Push(int x)
{}
//返回队列开头的数据
int Top()
{}
//判断是否为空
bool Empty()
{}
private:
queue<int> q1;
queue<int> q2;
};
3.2函数Push
在不为空的队列中插入数据即可(第一次插入数据的时候随便哪个队列插入数据)
//插入数据
void Push(int x)
{
if (q1.empty())
{
q2.push(x);
}
else//q1不为空
{
q1.push(x);
}
}
3.3函数Empty
用来判断栈是否为空,两队列都为空则栈为空
//判断是否为空
bool Empty()
{
return q1.empty() && q2.empty();
}
3.4函数Pop
将不为空的栈中数据除了队尾数据,都插入到另一个队列中。
然后删除这个队尾元素即可
//删除数据
void Pop()
{
//栈为空,不能够删除数据
if (Empty())
{
cout << "栈中没有数据可以删除!";
return;
}
if (!q1.empty())
{
//将不为空的队列中,除了队尾的数据都插入到另一个队列中
while (!q1.empty())
{
if (q1.size() == 1)
break;
q2.push(q1.front());
q1.pop();
}
//删除最后的数据
q1.pop();
}
else
{
while (!q2.empty())
{
if (q2.size() == 1)
break;
q1.push(q2.front());
q2.pop();
}
q2.pop();
}
}
3.5函数Top
返回栈顶元素,和pop类似,用一个变量t保留队尾元素即可
注意,在这个函数中,要将一个队列中所有的数据都插入到另外一个队列中
否则会删除元素,让栈出现错误删除
//返回队列开头的数据
int Top()
{
//栈为空,无栈顶元素
if (Empty())
{
cout << "栈中没有元素!";
exit(-1);
}
int t = 0;
if (!q1.empty())
{
//将不为空的队列中,除了队尾的数据都插入到另一个队列中
while (!q1.empty())
{
if (q1.size() == 1)
break;
q2.push(q1.front());
q1.pop();
}
//记录栈顶元素,注意要将所有的数据插入到另外一个队列中
t = q1.front();
q2.push(t);
q1.pop();
}
else
{
while (!q2.empty())
{
if (q2.size() == 1)
break;
q1.push(q2.front());
q2.pop();
}
t = q2.front();
q1.push(t);
q2.pop();
}
return t;
}
4.简单测试
测试代码如下
void test_stack()
{
MyStack s1;
s1.Push(1);
s1.Push(2);
s1.Push(3);
s1.Pop();
s1.Push(4);
s1.Push(5);
while (!s1.Empty())
{
cout << s1.Top() << " ";
s1.Pop();
}
}
int main()
{
test_stack();
return 0;
}
正确的结果应该尾 5 4 2 1
运行结果如下
5.整体代码
#include<iostream>
#include<queue>
using namespace std;
//利用两个队列实现栈
class MyStack
{
public:
MyStack()
{
queue<int> q1;
queue<int> q2;
}
//删除数据
void Pop()
{
//栈为空,不能够删除数据
if (Empty())
{
cout << "栈中没有数据可以删除!";
return;
}
if (!q1.empty())
{
//将不为空的队列中,除了队尾的数据都插入到另一个队列中
while (!q1.empty())
{
if (q1.size() == 1)
break;
q2.push(q1.front());
q1.pop();
}
//删除最后的数据
q1.pop();
}
else
{
while (!q2.empty())
{
if (q2.size() == 1)
break;
q1.push(q2.front());
q2.pop();
}
q2.pop();
}
}
//插入数据
void Push(int x)
{
if (q1.empty())
{
q2.push(x);
}
else//q1不为空
{
q1.push(x);
}
}
//返回队列开头的数据
int Top()
{
//栈为空,无栈顶元素
if (Empty())
{
cout << "栈中没有元素!";
exit(-1);
}
int t = 0;
if (!q1.empty())
{
//将不为空的队列中,除了队尾的数据都插入到另一个队列中
while (!q1.empty())
{
if (q1.size() == 1)
break;
q2.push(q1.front());
q1.pop();
}
//记录栈顶元素,注意要将所有的数据插入到另外一个队列中
t = q1.front();
q2.push(t);
q1.pop();
}
else
{
while (!q2.empty())
{
if (q2.size() == 1)
break;
q1.push(q2.front());
q2.pop();
}
t = q2.front();
q1.push(t);
q2.pop();
}
return t;
}
//判断是否为空
bool Empty()
{
return q1.empty() && q2.empty();
}
private:
queue<int> q1;
queue<int> q2;
};
void test_stack()
{
MyStack s1;
s1.Push(1);
s1.Push(2);
s1.Push(3);
s1.Pop();
s1.Push(4);
s1.Push(5);
while (!s1.Empty())
{
cout << s1.Top() << " ";
s1.Pop();
}
}
int main()
{
test_stack();
return 0;
}
6.LeetCode该题链接
在力扣中有这道题,我们将代码输入到力扣中看一下是否能够通过力扣的测试
题目链接 225. 用队列实现栈 - 力扣(LeetCode)
该题中,top要返回删除的元素,简单修改即可(top函数类似)
直接通过
7.总结
使用队列来模拟栈,只要注意将一个队列中的数据除了队尾以外都插入另一个队列中就很简单
在写数据结构相关的题画图可以帮忙我们快速解决问题
⭐“我画了你身边每一个人,但却没有画你。我觉得你亮得耀眼,使我的目光无法停留。”
留个赞吧!