本文章适用于了解过栈和队列结构的读者阅读,本文章代码使用c++实现!
目录
1.栈和队列的特点
栈和队列都是比较常见的数据结构
1.1: 栈的特点
栈的特点就是后插入的数据先出来,所谓后进先出。
一个经典的例子就是手枪中的子弹,最后压入的子弹最先打出来
1.2: 队列的特点
先插入的数据先出来,先进先出
一个经典的例子就是排队
2.如何使用两个栈实现一个队列?
假如面试官现在给你提供了两个完备的栈,你可以使用栈中的各种操作,如pop,push,top等。
最后能够实现队列中的pop,push,front等操作
本文使用c++ stl中的stack作为面试官提供的栈。
2.1分析结构
要实现队列操作,假如插入数据 1 2 3 4 5 ,那么最后输出 1 2 3 4 5
那么我们可以在第一个栈中插入数据,然后再将第一个栈中的数据弹出到第二个栈中
第二个栈在弹出数据给使用者即可完成
我们在第一个栈中插入数据
然后再将数据弹出并且插入到第二个栈中
由于栈的后进先出,所以栈2中的数据如下图所示
然后我们只要将栈2中的数据依次弹出即可得到队列输出的数据1 2 3 4 5
这样就能够模拟队列输入 1 2 3 4 5并且输出 1 2 3 4 5的操作
2.2注意事项!
假设我们称第一个栈为push栈,第二个栈为pop栈
每当我们将push栈中的数据弹出并且插入到pop栈的时候要将push栈中的所有数据到弹出并且插入到pop栈中,否则就会导致输出错误。
同上我们画图进行分析假设我们先插入了 1 2 3三个数据,最后因该输出 1 2 3
假设我们只吧 2 和 3 插入到第二个栈中,然后再弹出数据就会出错
输出的是 2 3 ,1没有输出
同理我们每次从pop栈弹出数据的时候要注意要将所有数据都输出之后,才能再次从push栈中插入新的数据
假设我们插入 1 2 3 ,然后输出 1 2 再插入4 5 最后输出 3 4 5
正确的输出因该是 1 2 3 4 5
如下流程图
然后我们输出 1 和 2
现在我们插入4 和 5并且在pop栈有数据的情况下
将push栈中的数据插入到pop栈中
这样的话,最后就会输出 4 5 3 出现错误
这是因为我们没有将3输出就插入了4和5,因该先弹出3就不会出现错误。
3.分析结束,开始写代码
3.1整体代码框架
#include<iostream>
#include<stack>
#include<assert.h>
using namespace std;
class MyQueue
{
public:
MyQueue()
{
stack<int> s_push;
stack<int> s_pop;
}
int pop()
{}
void push()
{}
int front()
{}
bool empty()
{}
private:
void PushToPop()
{}
stack<int> s_push;
stack<int> s_pop;
};
int main()
{
}
3.2函数PushToPop
由于我们在处理过程中,需要多次将push栈中的数据导入到pop栈中
所以在私有中写一个函数来完成这个功能,以提高代码的复用性和稳健性。
(此函数只能在类内部使用)
这个函数的功能为当pop栈为空的时候,将push栈中的所有数据插入到pop栈中
如果pop栈不为空,则不导入数据,防止出差
代码如下
void PushToPop()
{
//当pop栈为空时才导入数据
if (s_pop.empty())
{
//将push所有数据导入到pop栈中
while (!s_push.empty())
{
s_pop.push(s_push.top());//pop栈插入push栈的栈顶元素
s_push.pop();//push栈删除栈顶元素
}
}
}
3.3函数empty
此函数的功能是判断队列是否为空
如果pop栈和push栈都为空则说明,整个队列中没有元素
代码如下
bool empty()
{
return (s_pop.empty() && s_push.empty());
}
3.4函数push
直接在push栈中插入数据并且使用PushToPop函数判断能不能导数据即可
代码如下
void push(int x)
{
s_push.push(x);
PushToPop();
}
3.5函数front
这个函数的功能是返回队列最前面的元素(即pop栈的栈顶元素)
直接判断返回即可
代码如下
int front()
{
assert(!empty());//断言队列不为空,这里直接调用empty函数
PushToPop();//导数据
return s_pop.top();
}
3.6函数Pop
每次删除前使用PushToPop判断pop栈中是否为空,然后再删除数据即可
由于PushToPop函数只有pop栈为空才会导数据,所以不会导致错误地导数据
代码如下
int pop()
{
assert(!empty());//断言不为空
int t = front();//部分面试官在pop函数中要求返回pop的元素(就是队首的元素),这里记录一下
s_pop.pop();//删除pop
return t;
}
4.简单测试
测试代码如下
void test_Myqueue()
{
MyQueue q;
q.push(1);
q.push(2);
q.push(3);
q.pop();
q.push(4);
q.push(5);
q.push(6);
q.push(7);
q.pop();
//最后输出的因该是 3 4 5 6 7
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
}
int main()
{
test_Myqueue();
return 0;
}
运行结果如下图
5.整体代码
#include<iostream>
#include<stack>
#include<assert.h>
using namespace std;
class MyQueue
{
public:
MyQueue()
{
stack<int> s_push;
stack<int> s_pop;
}
int pop()
{
assert(!empty());//断言不为空
int t = front();//部分面试官在pop函数中要求返回pop的元素(就是队首的元素),这里记录一下
s_pop.pop();//删除pop
return t;
}
void push(int x)
{
s_push.push(x);
PushToPop();
}
int front()
{
assert(!empty());//断言队列不为空,这里直接调用empty函数
PushToPop();//导数据
return s_pop.top();
}
bool empty()
{
return (s_pop.empty() && s_push.empty());
}
private:
void PushToPop()
{
//当pop栈为空时才导入数据
if (s_pop.empty())
{
//将push所有数据导入到pop栈中
while (!s_push.empty())
{
s_pop.push(s_push.top());//pop栈插入push栈的栈顶元素
s_push.pop();//push栈删除栈顶元素
}
}
}
stack<int> s_push;
stack<int> s_pop;
};
void test_Myqueue()
{
MyQueue q;
q.push(1);
q.push(2);
q.push(3);
q.pop();
q.push(4);
q.push(5);
q.push(6);
q.push(7);
q.pop();
//最后输出的因该是 3 4 5 6 7
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
}
int main()
{
test_Myqueue();
return 0;
}
6.leetcode题目和题目链接
在力扣中有这道题,我们将代码输入到力扣中看一下是否能够通过力扣的测试
题目链接 232. 用栈实现队列 - 力扣(LeetCode)
由于在力扣中返回队首元素的函数名为peek,将front改为peek
点击提交后就能通过测试,并且用时超过100%。
7.总结
本体考察我们对栈和队列的了解程度,如果栈和队列都学的比较扎实此题因该不难!
只要注意两个注意事项即可!
下篇文章我会详细介绍如何使用两个队列来实现一个栈!
对你有用的话点个赞收藏关注一下吧~