用2个队列实现栈操作

一、文章来由

一道面试题,别说以前还真没好好想过,在未参考其他资料情况下自己想了两种,实现如下,如果另有高招,之后再补。

二、2种实现方式

分析:栈操作其实只有 push 和 pop 对栈内元素进行改变,我于是想从其一下手即可。

改变 push 操作:

比如输入,1 2 3 4 5,栈中结构应该是1在底,5在顶,但是队中元素是原顺序,如果要让push一个元素,让队列中的顺序反过来,就可以每推入一个元素,就用另一个队列中转把次序调整过来。

/*
*
* function: 用两个栈实现队列
*
* Date:2016-03-15
*
*    Author: Bill Wang
*/

#include <iostream>
#include <queue>

using namespace std;

template <class T>
class whStack
{
public:
    whStack(){}
    ~whStack(){}

    void push(T t);
    T pop();

private:
    std::queue<T> QueueA;
    std::queue<T> QueueB;
};

template<class T> void whStack<T>::push(T t) {

    //将另一个队列作为中转站

    //step1、将A队列所有元素推入B
    while ( !QueueA.empty() ) {
        T tmp = QueueA.front();
        QueueA.pop();
        QueueB.push(tmp);
    }

    //step2、推入新节点
    QueueA.push(t);

    //step3、将B队列回归A
    while ( !QueueB.empty() ) {
        T tmp = QueueB.front();
        QueueB.pop();
        QueueA.push(tmp);
    }

}

//pop时直接弹出并返回T
template<class T> T whStack<T>::pop() {

    T res = QueueA.front();
    QueueA.pop();
    return res;
}

int main()
{
    whStack<int > s;

    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    s.push(5);

    cout<<s.pop()<<endl;
    cout<<s.pop()<<endl;
    cout<<s.pop()<<endl;

    return 0;
}

这个输出:
5
4
3

但是这样相当于把另一个队列纯做中转,时间复杂度较高。

改变 pop 操作:

/*
*
* function: 用两个栈实现队列2
*
* Date:2016-03-15
*
*    Author: Bill Wang
*/

#include <iostream>
#include <queue>

using namespace std;

template <class T>
class whStack
{
public:
    whStack(){}
    ~whStack(){}

    void push(T t);
    T pop();

private:
    std::queue<T> QueueA;
    std::queue<T> QueueB;
};

template<class T> void whStack<T>::push(T t) {

    //判断哪一个队列非空
    if( !QueueA.empty() )
        QueueA.push(t);
    else
        QueueB.push(t);
}

//pop时直接弹出并返回T
template<class T> T whStack<T>::pop() {

    std::queue<T> &qa = QueueA.empty()? QueueB:QueueA;
    std::queue<T> &qb = QueueA.empty()? QueueA:QueueB;

    //将队尾最后一个元素留住,将其他元素入另一个队列
    T tmp;
    while (1) {

        tmp = qa.front();
        qa.pop();

        if( qa.empty() )
            break;

        qb.push(tmp);
    }

    return tmp;
}

int main()
{
    whStack<int > s;

    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    s.push(5);

    cout<<s.pop()<<endl;
    cout<<s.pop()<<endl;
    cout<<s.pop()<<endl;

    return 0;
}

同样输出:
5
4
3

三、复杂度分析

从源码可以看出,如果队列元素个数为n,他们的如果执行一对push和pop,都可以在线性时间 O(n),得出结果。

但是明显,第一种方法是将元素移进移出两次,一个队列始终为空,严格来说复杂度是 O(2n);第二种方法是两个队列轮流使用,省去一轮遍历,所以相较之下应该是 O(n),所以第二种更快一些。

时间: 2024-08-09 18:08:01

用2个队列实现栈操作的相关文章

《C++多线程编程实战》——1.9 链表、队列和栈示例

1.9 链表.队列和栈示例 下面的示例将演示线性链表(可包含任何泛型类型T)的OOP用法.该示例背后的思想是把继承作为表示"B是一种A"这种关系的模型. 线性链表是一种线性排列元素的结构,第1个元素链接第2个元素,第2个元素链接第3个元素,以此类推.线性链表的基本操作是,在线性链表中插入元素(PUT)和获取元素(GET).队列是一种线性链表,其中的元素按先进先出的次序排列,即FIFO(First In First Out).因此,从队列的顶部获取元素,从队列的底部插入新元素.栈也是一种

说清汇编中的栈操作地址问题

文章其实很简单,在这里只是想给大家一个提醒.让大家回顾一下曾经的知识而已,大学的知识,现在你还记得么? 另外,善意提醒下博客园团队,虽然我理解商业重要性,但是我个人还是希望把培训学校的广告撤下博客园首页的广告行列中,我相信博客园是一个纯洁的技术博客,大家对博客园都非常信任,我们不希望让太多的初学者受到这个影响,个人意见而已. 我刚才做一个小软件的破解,一直被堆栈的操作弄得昏昏沉沉,在这里写一下也算是加深一下自己的印象,做个总结,也希望能够提醒到大家. 步入正题,说说汇编中的栈操作. 首先,我们先

c++-关于C++的入栈和出栈操作

问题描述 关于C++的入栈和出栈操作 使用模板实现一个栈类,实现入栈和出栈操作,分别测试doubleintcharlongbool等类型 解决方案 http://wenku.baidu.com/link?url=FSCYEuOOM_QSZUMRDTi8NV8lyVP0G6pBXPzZ7SbH9ZLskbNUr6dHsX75CPgh1xH2pukZB40OozK9zSNHx4l1sGmesAOa6tAXGlDcLm2d21m 解决方案二: http://zhidao.baidu.com/link?

【数据结构之旅】顺序栈的定义、初始化、空栈判断、入栈、出栈操作

说明:     往前学习数据结构,想运行一个完整的顺序栈的程序都运行不了,因为书上给的都是一部分一部分的算法,并没有提供一个完整可运行的程序,听了实验课,自己折腾了一下,总算可以写一个比较完整的顺序栈操作的小程序,对于栈也慢慢开始有了感觉.下面我会把整个程序拆开来做说明,只要把这些代码放在一个文件中,用编译器就可以直接编译运行了. 一.实现 1.程序功能   关于栈操作的经典程序,首当要提及进制数转换的问题,利用栈的操作,就可以十分快速地完成数的进制转换. 2.预定义.头文件导入和类型别名   

谁能解释下&amp;amp;quot;递归的本质就是用压栈与出栈操作&amp;amp;quot;?

问题描述 谁能解释下"递归的本质就是用压栈与出栈操作"? 递归的本质就是用压栈与出栈操作 这句话感觉很有道理啊 解决方案 当递归调用时每次调用自己时可以看做是压栈过程,当递归条件满足结束时,递归一级一级的返回时可以看做是出栈的过程. 解决方案二: 函数调用的本质就是"压栈与出栈操作",递归不过是它的特例,自身调用自身. 解决方案三: 递归可以简单理解为一个大问题分为小问题,然后小问题继续分解,直到能解决,然后几个小问题解决,就是解决一个大问题,金字塔形状最后解决所有

汇编-c/c++ 函数调用中形参为指针或者引用对栈操作问题

问题描述 c/c++ 函数调用中形参为指针或者引用对栈操作问题 问题引出: 当我们的函数参数为普通变量或指针时,我们在调用过程中会拷贝一个副本,而当形参为引用时不会拷贝一个副本. 当形参为普通变量时,会拷贝一个变量备份,当为指针时会拷贝一个指针备份,指针指向的内容不会拷贝 问题来了: 查看使用指针和使用引用的方式调用的函数的汇编代码,会发现在汇编代码层面实现方式是一模一样的,都是: lea eax,[i](假设i是整形变量) push eax 而使用值传递方式是: mov eax,dword p

栈操作与栈帧 (转)

结构化程序的一个最基本的单元就是"函数"或者叫"过程".在汇编这一层自然也相应的有支持这些概念的指令操作,如栈操作和栈帧的概念. 首先这里要为"打开汇编之门"那篇blog补充一点的是:汇编语言是与机器相关,这里的一切都是基于IA-32机器平台的. 1.寻址方式我们已经知道在操作数表示中有一种是用来指示内存地址的内容的,在GNU Assembly中指示内存地址有多种方式,这些方式被统称"寻址方式".通用的寻址格式为:"

新人求教队列和栈的存取问题/xl

问题描述 以下都是什么意思啊?1.队列队头.forward.back2.栈顶.forward.back3.栈顶.back.forward 解决方案 解决方案二:队列FIFOfirstinfirstout先进先出栈FILOfirstinlastout先进后出楼主的问题,不明白解决方案三: 解决方案四:断开QHead.forward向后的链接让QHead指向QHead.forward解决方案五:你这是自己封装了一个双向链表的结构,每一个节点包含数据,前一节点和后一节点.通过forward和back可

java接口实现队列和栈

问题描述 使用接口编写一个程序,实现数据结构队列和栈指出思路即可,望高手指教!谢谢! 解决方案 解决方案二:publicinterfaceQueue{booleanadd(Objectobj);......}publicinterfaceStack{publicObjectpush(Objectitem);......}