1. 两个栈实现一个队列
这两道题并没有考察太多的算法,就是单纯对队列和栈特性的应用。
细节还是挺多需要注意的。
一个栈是无法完成队列操作的,我们要时刻记住队列的性质,先入先出。
入队列,我们可以按入栈进行操作,那么出队列呢,由于出队列是出队头的数据,我们不可能动栈底的数据,所以自然不能用一个栈。
所以我们用两个栈,一个栈用来入队列,一个栈用于出队列
//第一个栈用于入队列,第二个栈用于出队列
stack<int>stack1,stack2;
然后构造函数初始化
CQueue() {
while(!stack1.empty())
{
stack1.pop();
}
while(!stack2.empty())
{
stack2.pop();
}
}
入队列与入栈无差别
void appendTail(int value) {
stack1.push(value);
}
出队列需要先把在第一个栈里的数据放进第二个栈里。(因为我们要出栈底的数据不能直接出需要导入第二个栈,在第一个栈里是栈底,在第二个栈里是栈顶,然后出栈)就完成了出队列,符合先入先出
//第二个栈为空,才进行入第二个栈
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
//第二个栈不为空,返回栈顶数据
if(!stack2.empty())
{
int deleteNums=stack2.top();
stack2.pop();
return deleteNums;
}
那么为什么第二个栈为空,才进行新一轮的把第一个栈的数据往它里面进行导入呢。因为我一开始没有对第二个栈为空进行判断,导致逻辑出错。
原本应该是第二个栈为空才进行新一轮数据的导入,由于第二次模拟出队列我一开始没有对第二个栈进行判空,1刚出第二个栈,又把5导入了进来,正确的做法应该是等第二个栈里的数据全部出去,再倒入新的数据
完整代码
class CQueue {
//第一个栈用于入队列,第二个栈用于出队列
stack<int>stack1,stack2;
public:
CQueue() {
while(!stack1.empty())
{
stack1.pop();
}
while(!stack2.empty())
{
stack2.pop();
}
}
void appendTail(int value) {
stack1.push(value);
}
int deleteHead() {
//第二个栈为空,才进行入第二个栈
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
//第二个栈不为空,返回栈顶数据
if(!stack2.empty())
{
int deleteNums=stack2.top();
stack2.pop();
return deleteNums;
}
else
{
return -1;
}
}
};
2. 用栈实现队列
和上面的题逻辑一样,不过这道题函数接口完整一点。
无论是pop(出队列),还是peak(返回队头元素)
都需要检查当stack2为空时,把stack1的元素放进stack2。对stack2进行操作,所以其实可以把这段逻辑写成接口,不过太麻烦了,直接复制了,工程中注意代码复用性写成函数封装起来就好了。
完整代码
class MyQueue {
stack<int>stack1,stack2;
public:
/** Initialize your data structure here. */
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
stack1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
int removeNums=stack2.top();
stack2.pop();
return removeNums;
}
/** Get the front element. */
int peek() {
//栈2为空,把栈1的数据放进栈2里,用于出队列
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
//栈顶,相当于队头
return stack2.top();
}
/** Returns whether the queue is empty. */
bool empty() {
return stack1.empty()&&stack2.empty();
}
};
/**
* 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();
*/
3. 队列实现栈
开始就和上面一样想用两个队列实现,一个输入,一个输出,最后发现没啥用。因为你只能对队头进行操作。(像下图一样,出栈要的是4,你是队列只能对队头操作,只能拿到1,所以一个队列输入,一个队列输出是不行的。)
换一种思路,实现栈,无非就是先进后出,像上图,要想出4,我们让另一个队列暂时把除了最后一个之外的元素保存起来。然后pop掉q1的最后一个元素。q1清空
q1pop完成,符合栈的后入先出。那么接下来呢?还有其他数据。
交换两个队列(q2赋值给为空的q1,清空q2),使用前面相同的逻辑(另一个队列保存除了最后一个元素之外的数据,这个队列pop掉这个数据)
4 3 2 1就完成了先进后出。
依次迭代即可
完整代码
class MyStack {
queue<int>queue1,queue2;
public:
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
queue1.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int n=queue1.size()-1;
while(n)
{
int ret=queue1.front();
queue2.push(ret);
queue1.pop();
n--;
}
int stackTop=queue1.front();
queue1.pop();
//交换两个队列
// 相当于swap(queue1,queue2);
queue1=queue2;
//赋值给queue1后,清空queue2
while(!queue2.empty())
{
queue2.pop();
}
return stackTop;
}
/** Get the top element. */
int top() {
return queue1.back();
}
/** Returns whether the stack is empty. */
bool empty() {
return queue1.empty();
}
};
/**
* 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();
*/
4. STL中栈的接口
empty()//如果栈为空返回true,否则返回false
size()//返回栈中元素的个数
pop()//删除栈顶元素但不返回其值
top()//返回栈顶的元素,但不删除该元素
push(X)//在栈顶压入新元素 ,参数X为要压入的元素
5. STL中队列的接口
push(x) 将x压入队列的末端
pop() 弹出队列的第一个元素(队顶元素),注意此函数并不返回任何值
front() 返回第一个元素(队顶元素)
back() 返回最后被压入的元素(队尾元素)
empty() 当队列为空时,返回true
size() 返回队列的长度