题目:用递归颠倒一个栈。例如输入栈{1, 2, 3, 4, 5},1在栈顶。颠倒之后的栈为{5, 4, 3, 2, 1},5处在栈顶。

分析:乍一看到这道题目,第一反应是把栈里的所有元素逐一pop出来,放到一个数组里,然后在数组里颠倒所有元素,最后把数组中的所有元素逐一push进入栈。这时栈也就颠倒过来了。颠倒一个数组是一件很容易的事情。不过这种思路需要显示分配一个长度为O(n)的数组,而且也没有充分利用递归的特性。

我们再来考虑怎么递归。我们把栈{1, 2, 3, 4, 5}看成由两部分组成:栈顶元素1和剩下的部分{2, 3, 4, 5}。如果我们能把{2, 3, 4, 5}颠倒过来,变成{5, 4, 3, 2},然后在把原来的栈顶元素1放到底部,那么就整个栈就颠倒过来了,变成{5, 4, 3, 2, 1}。

接下来我们需要考虑两件事情:一是如何把{2, 3, 4, 5}颠倒过来变成{5, 4, 3, 2}。我们只要把{2, 3, 4, 5}看成由两部分组成:栈顶元素2和剩下的部分{3, 4, 5}。我们只要把{3, 4, 5}先颠倒过来变成{5, 4, 3},然后再把之前的栈顶元素2放到最底部,也就变成了{5, 4, 3, 2}。

至于怎么把{3, 4, 5}颠倒过来……很多读者可能都想到这就是递归。也就是每一次试图颠倒一个栈的时候,现在栈顶元素pop出来,再颠倒剩下的元素组成的栈,最后把之前的栈顶元素放到剩下元素组成的栈的底部。递归结束的条件是剩下的栈已经空了。这种思路的代码如下:

// Reverse a stack recursively in three steps:
// 1. Pop the top element
// 2. Reverse the remaining stack
// 3. Add the top element to the bottom of the remaining stack
template<typename T> void ReverseStack(std::stack<T>& stack)
{if(!stack.empty()){T top = stack.top();stack.pop();ReverseStack(stack);AddToStackBottom(stack, top);}
}

我们需要考虑的另外一件事情是如何把一个元素e放到一个栈的底部,也就是如何实现AddToStackBottom。这件事情不难,只需要把栈里原有的元素逐一pop出来。当栈为空的时候,push元素e进栈,此时它就位于栈的底部了。然后再把栈里原有的元素按照pop相反的顺序逐一push进栈。

注意到我们在push元素e之前,我们已经把栈里原有的所有元素都pop出来了,我们需要把它们保存起来,以便之后能把他们再push回去。我们当然可以开辟一个数组来做,但这没有必要。由于我们可以用递归来做这件事情,而递归本身就是一个栈结构。我们可以用递归的栈来保存这些元素。

基于如上分析,我们可以写出AddToStackBottom的代码:

// Add an element to the bottom of a stack:
template<typename T> void AddToStackBottom(std::stack<T>& stack, T t)
{if(stack.empty()){stack.push(t);}else{T top = stack.top();stack.pop();AddToStackBottom(stack, t);stack.push(top);}
}

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

程序员面试题精选100题(39)-颠倒栈[数据结构]相关推荐

  1. 程序员面试题精选100题(24)-栈的push、pop序列[数据结构]

    题目:输入两个整数序列.其中一个序列表示栈的 push 顺序,判断另一个序列有没有可能是对应的 pop 顺序.为了简单起见,我们假设 push 序列的任意两个整数都是不相等的. 比如输入的push序列 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. 191027爬虫笔记
  2. USACO / Stamps(DP)
  3. 从用户需求看互联网基础设施服务商www.shzhenai.com
  4. 使用泛型创建只读集合
  5. c语言中continue语句的作用是什么
  6. vuejs+webpack环境搭建
  7. CF - 1214D
  8. Android Studio .jar 包的引用方式(导入方式)
  9. Button.Text属性换行问题(Button.Bounds自动换行)
  10. 「洛谷5017」「NOIP2018」摆渡车【DP,经典好题】
  11. 201803101101_《函数的原始写法》
  12. IIS6.0文件解析漏洞
  13. Clickhouse时间日期函数一文详解+代码展示
  14. 力扣LeetBook<链表>学习笔记
  15. java代码运行的三个步骤,22年最新
  16. 一文带你浅入浅出Keepalived
  17. 如何解决收到网监大队信息系统安全等级保护限期整改通知书
  18. 浙江省计算机专业专科院校排名,浙江省高职院校“五强”
  19. 程序代码中常用英文单词使用总结
  20. 理解数据库范式(转)

热门文章

  1. c语言奇数值结点链表,习题11-7 奇数值结点链表 (20 分)
  2. C语言基础排序算法-冒泡排序
  3. Linux keypad 设备树,SC7731客户配置文档.pdf
  4. 谈谈mysql优化_浅谈MySQL SQL优化
  5. oracle v$system_event,45.Oracle杂记——Oracle常用动态视图v$system_event
  6. 什么是堆和栈以及区别详解
  7. 怎样在python代码中输入π_鼠标自动点击、键盘自动输入?几行Python代码搞定
  8. python集合的并集、交集_Python 集合set()添加删除、交集、并集、集合操作详解
  9. 微信小程序之生成图片保存到相册
  10. fluent计算进出口的流量差