题目:某队列的声明如下:

template<typename T> class CQueue
{
public:CQueue() {}~CQueue() {}void appendTail(const T& node);  // append a element to tailvoid deleteHead();               // remove a element from head private:T> m_stack1;T> m_stack2;
};

分析:从上面的类的声明中,我们发现在队列中有两个栈。因此这道题实质上是要求我们用两个栈来实现一个队列。相信大家对栈和队列的基本性质都非常了解了:栈是一种后入先出的数据容器,因此对队列进行的插入和删除操作都是在栈顶上进行;队列是一种先入先出的数据容器,我们总是把新元素插入到队列的尾部,而从队列的头部删除元素。

我们通过一个具体的例子来分析往该队列插入和删除元素的过程。首先插入一个元素a,不妨把先它插入到m_stack1。这个时候m_stack1中的元素有{a},m_stack2为空。再插入两个元素b和c,还是插入到m_stack1中,此时m_stack1中的元素有{a,b,c},m_stack2中仍然是空的。

这个时候我们试着从队列中删除一个元素。按照队列先入先出的规则,由于a比b、c先插入到队列中,这次被删除的元素应该是a。元素a存储在m_stack1中,但并不在栈顶上,因此不能直接进行删除。注意到m_stack2我们还一直没有使用过,现在是让m_stack2起作用的时候了。如果我们把m_stack1中的元素逐个pop出来并push进入m_stack2,元素在m_stack2中的顺序正好和原来在m_stack1中的顺序相反。因此经过两次pop和push之后,m_stack1为空,而m_stack2中的元素是{c,b,a}。这个时候就可以pop出m_stack2的栈顶a了。pop之后的m_stack1为空,而m_stack2的元素为{c,b},其中b在栈顶。

这个时候如果我们还想继续删除应该怎么办呢?在剩下的两个元素中b和c,b比c先进入队列,因此b应该先删除。而此时b恰好又在栈顶上,因此可以直接pop出去。这次pop之后,m_stack1中仍然为空,而m_stack2为{c}。

从上面的分析我们可以总结出删除一个元素的步骤:当m_stack2中不为空时,在m_stack2中的栈顶元素是最先进入队列的元素,可以pop出去。如果m_stack2为空时,我们把m_stack1中的元素逐个pop出来并push进入m_stack2。由于先进入队列的元素被压到m_stack1的底端,经过pop和push之后就处于m_stack2的顶端了,又可以直接pop出去。

接下来我们再插入一个元素d。我们是不是还可以把它push进m_stack1?这样会不会有问题呢?我们说不会有问题。因为在删除元素的时候,如果m_stack2中不为空,处于m_stack2中的栈顶元素是最先进入队列的,可以直接pop;如果m_stack2为空,我们把m_stack1中的元素pop出来并push进入m_stack2。由于m_stack2中元素的顺序和m_stack1相反,最先进入队列的元素还是处于m_stack2的栈顶,仍然可以直接pop。不会出现任何矛盾。

我们用一个表来总结一下前面的例子执行的步骤:

操作

m_stack1

m_stack2

append a

{a}

{}

append b

{a,b}

{}

append c

{a,b,c}

{}

delete head

{}

{b,c}

delete head

{}

{c}

append d

{d}

{c}

delete head

{d}

{}

总结完push和pop对应的过程之后,我们可以开始动手写代码了。参考代码如下:

///
// Append a element at the tail of the queue
///
template<typename T> void CQueue<T>::appendTail(const T& element)
{// push the new element into m_stack1m_stack1.push(element);
} ///
// Delete the head from the queue
///
template<typename T> void CQueue<T>::deleteHead()
{// if m_stack2 is empty, and there are some// elements in m_stack1, push them in m_stack2if(m_stack2.size() <= 0){while(m_stack1.size() > 0){T& data = m_stack1.top();m_stack1.pop();m_stack2.push(data);}}// push the element into m_stack2assert(m_stack2.size() > 0);m_stack2.pop();
}

扩展:这道题是用两个栈实现一个队列。反过来能不能用两个队列实现一个栈?如果可以,该如何实现?

本文(包括扩展的“用两个栈实现一个队列”)已经收录到《剑指Offer——名企面试官精讲典型编程题》一书中,有改动,书中的分析讲解更加详细。欢迎关注。

博主何海涛对本博客文章享有版权。网络转载请注明出处http://zhedahht.blog.163.com/。整理出版物请和作者联系

程序员面试题精选100题(18)-用两个栈实现队列[数据结构]相关推荐

  1. 程序员面试题精选100题(48)-二叉树两结点的最低共同父结点[数据结构]

    题目:二叉树的结点定义如下: struct TreeNode { int m_nvalue; TreeNode* m_pLeft; TreeNode* m_pRight; }; 输入二叉树中的两个结点 ...

  2. 程序员面试题精选100题

    程序员面试题精选100题(01)-把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向. 比如将二元查找树   ...

  3. 程序员面试题精选100题:41-50解题报告

    程序员面试题精选100题(41)-把数组排成最小的数[算法]   题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个.例如输入数组{32,  321},则输出这两个能 ...

  4. [程序员面试题精选100题]13.第一个只出现一次的字符

    [题目] 在一个字符串中找到第一个只出现一次的字符.如输入abaccdeff,则输出b. [分析] [代码] /********************************* * 日期:2013- ...

  5. 程序员面试题精选100题(51)-顺时针打印矩阵

    // 程序员面试题精选100题(51)-顺时针打印矩阵.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h" #include <iostre ...

  6. 程序员面试题精选100题:求从1到n的正数中1出现的次数

    // 程序员面试题精选100题(25):求从1到n的正数中1出现的次数 // 如 f(253) = (2!=0) * 100 + 2 * f(99) + (5!=0) * 10 + 5 * f(9) ...

  7. 程序员面试题精选100题:11-40解题报告

    程序员面试题精选100题(11)-求二元查找树的镜像[数据结构]   题目:输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点.用递归和循环两种方法完成 ...

  8. 程序员面试题精选100题(03)-子数组的最大和[算法]

    题目:输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). 例如输入的数组为1, -2, 3, ...

  9. [程序员面试题精选100题]19.反转链表

    题目 输入一个链表的头结点,反转该链表,并返回反转后链表的头结点. 分析 假设经过若干操作,我们已经把结点 pre之前的指针调整完毕,这些结点的next指针都指向前面一个结点.现在我们遍历到结点cur ...

最新文章

  1. Linux安装CentOS6(图文详解)新手入门
  2. Gartner 2019 年供应链技术八大趋势:AI、高级分析、物联网、RPA、自主设备、数字孪生...
  3. FPGA的设计艺术(8)最佳的FPGA开发实践之严格遵循过程
  4. Java NIO (五) 管道 (Pipe)
  5. 如何查看python是多少位的-请问一下该怎么查看python是32位还是64位?
  6. Windows服务BAT命令-安装、卸载、启动、停止
  7. 静态数组和动态数组 内存分布
  8. linux里工作目录的字体变蓝,netterm访问Linux时字体和背景颜色随目录发生改变的问题解决...
  9. Windows底层窗口的实现———学习笔记
  10. C++学习系列笔记(六)
  11. db文件 linux查看工具,Linux最大文件句柄数查看及修改
  12. [转载] Java中方法不可以有默认参数
  13. Javascript 权威指南第五版 手记(1) 引用类型
  14. 高通9008刷机大法,避坑指南,救砖前提
  15. 单目标跟踪——常用数据集和指标
  16. JDBC练习1 从控制台向数据库的表customers中插入一条数据
  17. 利用python构建马科维茨_使用CVXOPT包实现马科维茨投资组合优化
  18. 青龙面板+傻妞sillyGirl+阿东自动登录全套保姆级一步到位教程(2021-10-09)
  19. 兔子繁殖问题。假设有一对小兔子,一个月后成长为一对大兔子,从 第二个月开始,每对大兔子生一对小兔子。不考虑兔子的死亡,求第n个月的兔子总对数
  20. 联合体union内有数组的情况

热门文章

  1. 十分钟教你开发EOS智能合约
  2. 比特币与企业级区块链的区别
  3. 百度大脑险胜最强大脑背后:200万人2亿照片做训练
  4. Gradient Boost 算法流程分析
  5. MySQL - 剖析MySQL索引底层数据结构
  6. Elasticsearch-06 Spring Boot 2.0.9整合ElasticSearch5.6.16
  7. Linux执行yum不显示时间,Linux停的yum命令详解(朝花夕拾)
  8. wait/notify/notifyAll在Object类中
  9. 使用Kotlin写脚本
  10. ROS知识【13】:ubuntu下安装eclipse-CDT【非installor】