栈和队列面试题:

  • 实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)
  • 使用两个栈实现一个队列
  • 使用两个队列实现一个栈
  • 元素出栈、入栈顺序的合法性。如入栈的序列(1,2,3,4,5),出栈序列为 (4,5,3,2,1)
  • 一个数组实现两个栈(共享栈)

实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1) 

问题分析:栈的入栈操作和出栈操作时间复杂度本来就是O(1),所以这道题目的关键点在于如何处理才能做到返回栈中最小值时的时间复杂度也为O(1)

方法一:用一个栈

入栈:第一个元素入栈时(当前栈为空),push 两次第一个数据,第一次 push 的数据代表当前入栈的数据,第二次 push 的数据代表当前栈中最小的元素;第二个元素入栈时,先将该数据与当前栈顶的数据进行比较并记录下二者当中较小的数据,然后 push 第二个数据,接个 push 比较后记录的较小的那个数据(该数据就是当前栈中的最小值);后面入栈的数据做同样的处理

出栈:出栈时需 pop 两次,第一次 pop 的结果是当前栈中最小的元素,第二次 pop 的结果是真真意义上的栈顶元素

取最小值:当前栈顶的元素就是栈中所有元素的最小值

说明:方式一下的栈接口与普通的栈接口一模一样,这里的代码前一篇博客已经实现了,可以参考:数据结构—栈

方式二:用两个栈

入栈:第一个元素入栈时(栈为空),栈 S1和S2 中都 push 第一个数据,栈S1中的数据代表当前入栈的数据,栈S2中的数据代表当前栈中最小的数据;第二个数据入栈时(假设栈不为空),栈S1中直接 push 第二个数据,然后比较第二个数据和S2栈顶的数据并记录下较小的那个数据,将记录下的较小值 push 到S2中作为当前栈中最小的数据;后面入栈的数据做同样的处理

出栈:同时 pop 栈S1和S2,栈S1进行 pop 的结果是删除当前栈顶的元素,栈S2进行 pop 的结果是更新了栈中的最小元素记录

取最小值:栈S2栈顶的元素就是当前所有元素中的最小值

结构的定义:

typedef struct MinStack  //最小值栈
{
         Stack _s1;  //存数据
         Stack _s2;  //存当前栈中数据的最小值
}MinStack;

基本接口实现:

void MinStackInit(MinStack* ms)
{assert(ms);StackInit(&ms->_s1);StackInit(&ms->_s2);
}void MinStackPush(MinStack* ms,DataType x)
{assert(ms);if (StackEmpty(&ms->_s1) == 0)  //说明栈为空,将第一个数据直接 push 到两个栈中{StackPush(&ms->_s1, x);StackPush(&ms->_s2, x);return;  //这里的 return 千万不能忘}//走到这里说明栈中已经有了数据DataType min = StackTop(&ms->_s2) < x ? StackTop(&ms->_s2) : x;StackPush(&ms->_s1, x);StackPush(&ms->_s2, min);
}void MinStackPop(MinStack* ms)  //出栈
{assert(ms);StackPop(&ms->_s1);StackPop(&ms->_s2);
}DataType MinStackTop(MinStack* ms)  //栈顶元素
{assert(ms);return StackTop(&ms->_s1);
}DataType MinStackMinDate(MinStack* ms)  //查看当前栈中的最小元素
{assert(ms);return StackTop(&ms->_s2);
}size_t MinStackSize(MinStack* ms)  //求栈中元素个数
{assert(ms);return StackSize(&ms->_s1);
}int MinStackEmpty(MinStack* ms)  //判断栈是否为空
{assert(ms);return StackEmpty(&ms->_s1);
}

使用两个栈实现一个队列

问题说明:用两个栈实现队列的过程中必须要保证栈特征,即先进后出的原则,只是对外表现出队列的特性罢了

结构的定义:

typedef struct QueueByStack  //队列
{
         Stack _s1; 
         Stack _s2; 
}QueueByStack;

基本接口实现:

void QueueByStackInit(QueueByStack* q)  //队的初始化
{assert(q);StackInit(&q->_s1);StackInit(&q->_s2);
}void QueueByStackPush(QueueByStack* q,DataType x)  //入队
{assert(q);StackPush(&q->_s1,x);
}void QueueByStackPop(QueueByStack* q)  //出队
{assert(q);if (StackEmpty(&q->_s2) == 0)  //S2为空{if (StackEmpty(&q->_s1) == 0)  //S1也是空,说明队列无数据可删return;while (StackEmpty(&q->_s1)) {  //将S1中的所有数据push到S2StackPush(&q->_s2,StackTop(&q->_s2));StackPop(&q->_s1);}}//走到这里说明S2不为空,直接删就行StackPop(&q->_s2);
}size_t QueueByStackSize(QueueByStack* q)  //求队列的元素个数
{assert(q);return StackSize(&q->_s1)+StackSize(&q->_s2);  //两个栈中元素的总和才是队列的元素个数
}int QueueByStackEmpty(QueueByStack* q)
{assert(q);return StackEmpty(&q->_s1) + StackEmpty(&q->_s2);  //这里两个栈都要做判断
}

使用两个队列实现一个栈 

关于栈顶元素:根据栈的性质,出栈的元素就是栈顶的,所以寻找栈顶的元素的方法和找出栈的元素的方法是一样的

结构的定义:

typedef struct StackByQueue  //栈
{
       Queue _q1;
       Queue _q2;
}StackByQueue;

基本操作接口实现:

typedef struct StackByQueue
{Queue _q1;Queue _q2;
}StackByQueue;void StackByQueueInit(StackByQueue* q)  //初始化
{assert(q);QueueInit(&q->_q1);QueueInit(&q->_q2);
}int StackByQueueEmpty(StackByQueue* q)  //判断栈是否为空
{assert(q);return QueueEmpty(&q->_q1) + QueueEmpty(&q->_q2);
}void StackByQueuePush(StackByQueue* q,DataType x)  //入队
{assert(q);QueuePush(&q->_q1,x);
}void StackByQueuePop(StackByQueue* q)  //出队
{assert(q || StackByQueueEmpty(q) == 0);if (QueueSize(&q->_q1) > 1)  //第一种情况,出栈时q1中有多个元素{while (QueueSize(&q->_q1) > 1) {QueuePush(&q->_q2,QueueHead(&q->_q1));QueuePop(&q->_q1);}}else if(QueueSize(&q->_q1) == 0)  //第二种情况,出栈时q1为空{//先将q2中的元素全部push到q1中while (QueueSize(&q->_q2) != 0) {QueuePush(&q->_q1,QueueHead(&q->_q2));QueuePop(&q->_q2);}//现在不断push队列q1中的元素到q2,直至q1中只剩下一个元素while (QueueSize(&q->_q1) != 1) {QueuePush(&q->_q2, QueueHead(&q->_q1));QueuePop(&q->_q1);}}//走到这里说明q1中只有一个元素,直接pop即可QueuePop(&q->_q1);
}DataType StackByQueueHead(StackByQueue* q)  //查看栈顶元素
{//栈顶的元素和出栈的元素寻找方法是一样的assert(q || StackByQueueEmpty(q) == 0);if (QueueSize(&q->_q1) > 1)  //第一种情况,出栈时q1中有多个元素{while (QueueSize(&q->_q1) > 1) {QueuePush(&q->_q2, QueueHead(&q->_q1));QueuePop(&q->_q1);}}else if (QueueSize(&q->_q1) == 0)  //第二种情况,出栈时q1为空{//先将q2中的元素全部push到q1中while (QueueSize(&q->_q2) != 0) {QueuePush(&q->_q1, QueueHead(&q->_q2));QueuePop(&q->_q2);}//现在不断push队列q1中的元素到q2,直至q1中只剩下一个元素while (QueueSize(&q->_q1) != 1) {QueuePush(&q->_q2, QueueHead(&q->_q1));QueuePop(&q->_q1);}}else  //走到这里说明q1中只有一个元素,即为栈顶元素{return QueueTail(&q->_q1);}return QueueTail(&q->_q1);
}size_t StackByQueueSize(StackByQueue* q)
{assert(q);return QueueSize(&q->_q1)+QueueSize(&q->_q2);
}

元素出栈、入栈顺序的合法性。如入栈的序列(1,2,3,4,5),出栈序列为 (4,5,3,2,1) 

问题分析:

我相信上面的这种思路是绝大数人首先想到的,并且很有可能会在自己脑海保存这个答案,认为这是这个题目的标准答案,因为这种思路对绝大数出栈序列的判断是没有问题的,如果你不做详细的测试,或者说测试用例不够的话的确是这样

下面我们说下这里面存在的一个坑

当入栈顺序为:1 2 3 4 5 时 3 2 4 1 5 也是一个合法的出序列,你按上面思路走走,判断出来却是不合法

建议用我给的测试用例走走上面这个过程,自己理解清楚这样做的实质

代码实现:


int CheckInvaliOutStackOrder(int* a1,int* a2,int n)
{int i = 0,index = 0, outdex = 0;Stack s;StackInit(&s);while (index < n) {if (a1[index] == a2[outdex]){++index;++outdex;}else{if (StackEmpty(&s) != 0 && StackTop(&s) == a2[outdex]){StackPop(&s);++outdex;}else{StackPush(&s, a1[index]);++index;}}}int j = outdex;while(j < n){if (StackTop(&s) == a2[outdex]){++outdex;StackPop(&s);}elsereturn 0;  //出栈序列不合适++j;}return 1;  //出战序列合适
}

一个数组实现两个栈(共享栈)

问题分析: 这个题比较简单,了解清楚用一个数组实现栈的结构特点就可以,这里我提供将一个数组分配给两个栈用的三种结构(摘自一篇博客;http://blog.csdn.net/sssssuuuuu666/article/details/78723541)

说明:

方法一:采用交叉索引的方式,数组奇数位为一个栈,偶数位为一个栈;每次push,pop操作找到对应的下标进行操作;

方法二:可计算出数组中间位置,左半部分为栈1,右半部分为栈2;

方法三:相对于前两种比较优的解决方法,栈1从数组下标为0开始不断增大,栈2从数组元素个数-1的下标开始不断减小。

相比三种方法,效率不相上下,第一二种考虑增容时会比较麻烦,第三种较简单;第一种和第二种方法在其中一个栈压入比较多的数据而另外一个栈数据很少时,就存在非常大的空间浪费,但方法三就可以很好的避免这一情况,空间利用率比较高,而且这种方案在一个栈pop的空间另一个栈可以使用,可以在一些情况下减少开辟空间的次数。

数据结构—栈和队列经典面试题相关推荐

  1. 【数据结构 C语言版】第六篇 栈、队列经典必刷面试考研题

    [数据结构 C语言版]第六篇 栈.队列经典必刷面试考研题 写在前面 更新情况记录: 最近更新时间 更新次数 2022/10/20 1 参考博客与书籍以及链接: (非常感谢这些博主们的文章,将我的一些疑 ...

  2. java为什么不推荐使用stack_栈和队列的面试题Java实现,Stack类继承于Vector这两个类都不推荐使用...

    在 thinking in java中看到过说Stack类继承于Vector,而这两个类都不推荐使用了,但是在做一到OJ题时,我用LinkedList来模拟栈和直接用Stack,发现在进行入栈出栈操作 ...

  3. 数据结构——栈与队列相关题目

    数据结构--栈与队列相关题目 232. 用栈实现队列 思路 225. 用队列实现栈 1.两个队列实现栈 2.一个队列实现栈 20. 有效的括号 思路 1047. 删除字符串中的所有相邻重复项 思路 1 ...

  4. 数据结构栈和队列_使您的列表更上一层楼:链接列表和队列数据结构

    数据结构栈和队列 When you want to store several elements somewhere in a program, the go-to data type is an a ...

  5. 数据结构栈与队列的应用之汽车轮渡问题——自己的一些理解

    本题摘自王道数据结构栈与队列的应用的课后题,题目如下: 某汽车轮渡口,过江渡船每次能载10辆汽车过江.过江车辆分为客车类和货车类,上渡船有如下规定:同类车先到先上船,客车先于货车上船,且每上4辆客车, ...

  6. 第十章 基本数据结构——栈和队列

    摘要 本章介绍了几种基本的数据结构,包括栈.队列.链表以及有根树,讨论了使用指针的简单数据结构来表示动态集合.本章的内容对于学过数据结构的人来说,没有什么难处,简单的总结一下. 1.栈和队列 栈和队列 ...

  7. 大话数据结构-栈与队列

    文章知识点来至于大话数据结构里边章节知识, 这篇主要介绍栈与队列在计算机中存储形式, 以及在某些算法领域中对栈和队列的相关应用.章节最后介绍了著名的逆波兰表达式, 以及通过算法来实现该表达式的运算过程 ...

  8. 数据结构——栈与队列操作(用栈模拟队列)

    [栈与队列操作] 问题描述:假设有两个长度相同的栈 S1,S2,已知以下入栈.出栈.判栈满和判栈空操作: void Push(S,x); Elemtype Pop(S); bool StackFull ...

  9. 【数据结构-栈和队列】详解栈和队列(代码+STL+原理)

    一.栈的应用 栈是一种先进后出(FILO)的数据结构 1.1 栈的操作实现 清空(clear): // 栈的清空操作就是把栈顶top置为-1 void clear(){top=-1; } // 清空栈 ...

最新文章

  1. 计算机二级理工类报哪个,计算机二级考哪一科目,毕业后找工作会对科目有要求吗?还是说不管什么科目有证就行了?...
  2. linux学习总结-----web前端①
  3. 判断long类型是否为空_数据类型
  4. Java多线程安全问题解决的两种方式代码案例
  5. Win7蓝屏代码0x000000001e怎么解决
  6. Nginx学习总结(12)——Nginx各项配置总结
  7. Linux运维六:用户管理及用户权限设置
  8. .NET开发设计模式-获取某个接口下面所有的派生类
  9. 国外手机短信验证码接收神器(转自美国华人网FuninUSA)
  10. Software Architecture Pattern(Mark Richards)笔记
  11. 中国省市地图json数据包及解析
  12. php excel 设置下拉菜单,phpexcel setFormula下拉选择列表 序列
  13. android 表情键盘切换,如何在键盘之间切换(从表情符号到qwerty,反之亦然)
  14. Android Studio报错Could not find any version that matches com.android.support:appcompat-v7:33.+.
  15. 路由器、交换机、服务器等网络设备常见故障及解决方法
  16. 绝缘栅型n沟道场管_N沟道增强型绝缘栅场效应管的工作原理
  17. 千峰软件测试学习营 第七章
  18. 破解flashFXP密码全过程
  19. rtmp直播和webrtc直播对比优劣何在?
  20. 图像转文本、PDF 转文字(包括html、xml)、关键句提取 软件开发手记

热门文章

  1. 方差、标准差、均方误差
  2. 三极管 场效应管(MOS管) 引脚
  3. MakeItTalk: 让图像开口说话!
  4. There was an error while executing `VBoxManage`, a CLI used by Vagrant for controlling VirtualBox.错误
  5. Allegro PCB 软件自动检查走线是否跨分割
  6. win10计算机右键属性打不开,右键电脑属性打不开|解决win10系统我的电脑属性打不开...
  7. RSA的非对称加密,公钥加密私钥解密,本地测试
  8. mysql忘记初始密码与更改密码
  9. openldap简介
  10. VC++ 操作Word