[数据结构] 用两个栈实现队列详解

简介: 在数据结构中,栈和队列是较为常见的两种数据结构。他们各有自己的特点:栈是后进先出原则,队列是先进先出原则。那怎么用栈去实现队列呢?此问题在面试中也是高频出现的问题。本篇文章会给出详细解释。

 在数据结构中,栈和队列是较为常见的两种数据结构。他们各有自己的特点:栈是后进先出原则,队列是先进先出原则。那怎么用栈去实现队列呢?此问题在面试中也是高频出现的问题。本篇文章会给出详细解释。



一、栈实现队列的特点分析

1、1 具体分析



 队列和栈在插入数据时,队列是从队尾进行插入,栈是从栈顶插入。但是他们的删除数据是不同的。我们知道队列的特点是:先新先出 ,删除数据是在对头进行删除,栈的特点是:先进后出,也就是在栈顶进行删除。


 当我们用栈实现队列时,最根本的也是最重要的是需要解决删除的问题。我们用栈实现队列时,在栈中的删除就不是删除栈顶的元素了,我们需要根据队列的特点进行删除,也就是我们需要删除的是栈底的元素。



63adcb5d7bc64755897f9da28f17b15a.png

怎么删除栈底的元素呢?在这里我们需要两个栈,分别命名为push栈pop栈。我们先把元素的插入全部插入到push栈中,当需要删除时,我们首先把push栈中的元素全部导入到pop栈中,此时的pop栈中的栈顶元素,相当于我们要删除的对头元素了。



f3d02df5549e4912b65f23b43c11e235.png


 那如果我们想要接着插入呢?我们接着往push栈中插入即可。删除的话我们看pop栈中是否有元素,如果pop栈不为空,就接着删除如果pop栈为空,我们需要把push栈的元素再次导入到pop栈中删除即可。具体流程我们可以结合下图(gif)理解:


81641a0c1931489f9da8d5039d14c175.gif





1、2 整体概括


 用栈模拟队列我们整体的思路分为以下几步:


我们需要先定义两个栈,分别为push栈和pop栈;

插入数据到往push栈中;

删除数据时,需要先判断pop栈是否为空。如果为空,需要将push栈的所有数据导入到pop栈中。如果不为空,就直接在pop栈删除即可。

再插入数据时,就往push栈中插入即可。

 以上即为用栈模拟队列的全过程,那我们来看代码的实现。


二、用栈模拟队列代码的实现

 这里我们用c语言进行实现。所以我们这里需要先手撕出一个栈。



2、1 手撕 栈 代码

2、1、1 stack.h

#define INT_CAPACITY 4
typedef int STDataType;
typedef struct stack
{
  STDataType* a;
  int top;
  int capacity;
}ST;
void STInit(ST* ps);
void STDestory(ST* ps);
bool STIsEmpty(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
int STSize(ST* ps);
STDataType STTop(ST* ps);


2、1、2 stack.c

void STInit(ST* ps)
{
  assert(ps);
  ps->a = (STDataType*)malloc(sizeof(STDataType)* INT_CAPACITY);
  if (ps->a == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  ps->top = 0;
  ps->capacity = INT_CAPACITY;
}
void STDestory(ST* ps)
{
  assert(ps);
  free(ps->a);
  ps->capacity = 0;
  ps->top = 0;
}
bool STIsEmpty(ST* ps)
{
  assert(ps);
  return ps->top==0;
}
void STPush(ST* ps, STDataType x)
{
  assert(ps);
  if (ps->top == ps->capacity)
  {
    STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
    if (tmp == NULL)
    {
      perror("realloc fail");
      exit(-1);
    }
    ps->a = tmp;
    ps->capacity *= 2;
  }
  ps->a[ps->top++] = x;
}
void STPop(ST* ps)
{
  assert(ps);
  assert(!STIsEmpty(ps));
  ps->top--;
}
int STSize(ST* ps)
{
  assert(ps);
  return ps->top;
}
STDataType STTop(ST* ps)
{
  assert(ps);
  assert(!STIsEmpty(ps));
  return ps->a[ps->top - 1];
}


2、2 用栈实现队列代码

这个是OJ链接( 用栈实现队列 - OJ链接(力扣)),大家可以直接点开链接用其他语言做一下。我们看C语言的代码实现。

#define INT_CAPACITY 4
typedef int STDataType;
typedef struct stack
{
  STDataType* a;
  int top;
  int capacity;
}ST;
void STInit(ST* ps);
void STDestory(ST* ps);
bool STIsEmpty(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
int STSize(ST* ps);
STDataType STTop(ST* ps);
void STInit(ST* ps)
{
  assert(ps);
  ps->a = (STDataType*)malloc(sizeof(STDataType)* INT_CAPACITY);
  if (ps->a == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  ps->top = 0;
  ps->capacity = INT_CAPACITY;
}
void STDestory(ST* ps)
{
  assert(ps);
  free(ps->a);
  ps->capacity = 0;
  ps->top = 0;
}
bool STIsEmpty(ST* ps)
{
  assert(ps);
  return ps->top==0;
}
void STPush(ST* ps, STDataType x)
{
  assert(ps);
  if (ps->top == ps->capacity)
  {
    STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
    if (tmp == NULL)
    {
      perror("realloc fail");
      exit(-1);
    }
    ps->a = tmp;
    ps->capacity *= 2;
  }
  ps->a[ps->top++] = x;
}
void STPop(ST* ps)
{
  assert(ps);
  assert(!STIsEmpty(ps));
  ps->top--;
}
int STSize(ST* ps)
{
  assert(ps);
  return ps->top;
}
STDataType STTop(ST* ps)
{
  assert(ps);
  assert(!STIsEmpty(ps));
  return ps->a[ps->top - 1];
}
typedef struct 
{
    ST StackPop;
    ST StackPush;
} MyQueue;
MyQueue* myQueueCreate()
{
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->StackPop);
    STInit(&obj->StackPush);
    return obj;
}
void myQueuePush(MyQueue* obj, int x) 
{
    STPush(&obj->StackPush,x);
}
int myQueuePeek(MyQueue* obj) 
{
    if(STSize(&obj->StackPop)==0)
    {
        while(STSize(&obj->StackPush)!=0)
        {
            STPush(&obj->StackPop,STTop(&obj->StackPush));
            STPop(&obj->StackPush);
        }
    }
    return STTop(&obj->StackPop);
}
int myQueuePop(MyQueue* obj) 
{
    int ret=myQueuePeek(obj);
    STPop(&obj->StackPop);
    return ret;
}
bool myQueueEmpty(MyQueue* obj) 
{
    return STSize(&obj->StackPop)==0 && STSize(&obj->StackPush)==0;
}
void myQueueFree(MyQueue* obj) 
{
    STDestory(&obj->StackPop);
    STDestory(&obj->StackPush);
    free(obj);
}


相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
210 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
35 1
|
27天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
53 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
49 0
|
2月前
数据结构(栈与列队)
数据结构(栈与列队)
23 1
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
48 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器