用栈模拟实现队列(c语言版)

简介: 用栈模拟实现队列(c语言版)

前言


用"栈实现队列",力扣中一道oj题,可以帮助刚接触"栈"和"队列"的新手更好的理解栈和队列这两种结构.


题目来源于力扣:


题目链接:https://leetcode.cn/problems/implement-queue-using-stacks/


难度:简单


一、队列的各接口:


1.1 类型的声明(MyQueue):


//模拟队列类型的声明
typedef struct {
    ST stackpush;   //用于模拟队列的 入队操作
    ST stackpop;    //用于模拟队列的 出队操作
} MyQueue;


这里是借助两个栈用于模拟队列.


①:stackpush 模拟队列的入队


②:stackpop 模拟队列的出队



1.2 初始化(myQueueCreate):


该队列是由两个栈实现的,所以重点关注两个栈的初始化即可.


步骤:


  1. 申请两个栈大小的空间.


申请失败时判断一下.


  1. 对队列中的两个栈,一次调用他们的初始化函数.(这个千万别漏掉了,牛牛漏掉之后找了好久的问题)


//队列的初始化
MyQueue* myQueueCreate() {
  //给队列开辟空间
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("obj malloc fail");
    }
    //一定要记得这里要初始化(别漏掉了哦)
    InitST(&obj->stackpush);
    InitST(&obj->stackpop);
    return obj;
}


1.3 入队列(myQueuePush)


对于入队列的模拟实现很简单,只需要将数据压入栈(模拟入队列:stackpush)即可.


void myQueuePush(MyQueue* obj, int x) {
    assert(obj);
    STPush(&obj->stackpush,x);
}


1.4 出队列(myQueuePop)


函数要求:


将队首元素出队,并且返回刚刚出队的队首元素.


模拟出队相对复杂一些.


  1. 初始状态下或者stackpop(模拟出队的栈)数据出队列到空时,里面是没有数据的,所以先判断stackpop是否有数据.


有数据:则直接获取stackpop的栈顶元素作为队首元素.


无数据:将数据从模拟入队列栈全部倒过来.(倒数据)


  1. 获取stackpop的栈顶元素作为队首元素,使用top变量记录下来.(因为后面要执行出栈操作).


  1. 出栈(模拟出队列),并返回top变量.


int myQueuePop(MyQueue* obj) {
     assert(obj);
     if(STEmpty(&obj->stackpop))//如果栈(stackpop模拟出队列的栈)为空,则向栈(stackpush模拟入队列的栈)要数据
     {
        //下面循环结束的条件是不为空
          while(!STEmpty(&obj->stackpush))//将数据从模拟入队列栈全部倒过来
        {
            //将栈(stackpush模拟入队)的栈顶元素依次压入栈(stackpop模拟出栈)
            STPush(&obj->stackpop,STTop(&obj->stackpush));
            STPop(&obj->stackpush);
        }
     }
    int top=STTop(&obj->stackpop);//记录用来模拟出队列的栈的栈顶元素;
    STPop(&obj->stackpop);
    return top;
}


1.5 队列的判空(myQueueEmpty)


当两个栈中都没有元素时,则队列为空.


//写法1


bool myQueueEmpty(MyQueue* obj) {
    if(STEmpty(&obj->stackpush)&&STEmpty(&obj->stackpop))//如果都为空,则为空栈
    {
        return true;
    }
    else 
    return false;
}


//写法2.


bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->stackpush) &&  STEmpty(&obj->stackpop);
}


1.6 返回队首元素(myQueuePeek):


  1. stackpop不为空时,则队首元素就是stackpop的栈顶元素.


  1. stackpop为空时,则队首元素就是stackpush的栈底元素.


所以这里也需要倒数据.


int myQueuePeek(MyQueue* obj) {
    assert(obj);
    if(STEmpty(&obj->stackpop))//如果栈(stackpop模拟出队列)为空,则向栈(stackpush模拟入队列)要数据
     {
        while(!STEmpty(&obj->stackpush))
        {
            //将栈(stackpush模拟入队)的栈顶元素依次压入栈(stackpop模拟出队列)
            STPush(&obj->stackpop,STTop(&obj->stackpush));
            STPop(&obj->stackpush);
        }
    }
    int top=STTop(&obj->stackpop);//记录用来模拟出队列的栈的栈顶元素;
    return top;
}


与myQueuePop(出队列)函数比较,此函数只是将队首元素返回,并没有指向pop出队操作.


所以我们在实现myQueuePop函数时可以复用一下myQueuePeek函数.


int myQueuePop(MyQueue* obj) {
    int top=myQueuePeek(obj);
    STPop(&obj->stackpop);
    return top;
}


1.7 队列的销毁(myQueueFree):


  1. 释放两个栈初始化开辟的空间


  1. 释放队列申请的空间.


void myQueueFree(MyQueue* obj) {
    STDestory(&obj->stackpush);
    STDestory(&obj->stackpop);
    free(obj);
}


二、总代码:


前面的代码是栈的实现,由于c语言不能像c++那样直接调用库.


typedef  int stacktype;
typedef struct stack//定义栈的类型
{
  stacktype* data;
  int top;
  int capacaity;
}ST;
void InitST(ST* ps);//初始化栈
void STPush(ST* ps, stacktype x);//压栈
void STPop(ST* ps);//出栈
bool STEmpty(ST* ps);//判断是否为空栈
stacktype STTop(ST* ps);//返回栈顶元素
void STDestory(ST* ps);//栈的销毁
void InitST(ST* ps)//初始化栈
{
  assert(ps);
  ps->top = -1;
  ps->capacaity = 4;
  ps->data = (stacktype*)malloc(ps->capacaity * sizeof(stacktype));
}
void STPush(ST* ps, stacktype x)//压栈
{
  assert(ps);
  if (ps->top+1 == ps->capacaity)
  {
    ps->capacaity *= 2;
    ST* tmp = (stacktype*)realloc(ps->data, ps->capacaity * sizeof(stacktype));
    if(tmp == NULL)
    {
      printf("增容失败\n");
    }
    ps->data = tmp;
  }
  ps->top++;
  ps->data[ps->top] = x;
}
void STPop(ST* ps)//出栈
{
  assert(ps);
  assert(!STEmpty(ps));
  ps->top--;
}
bool STEmpty(ST* ps)//判断是否为空栈,是空返回真
{
  assert(ps);
  if (ps->top == -1)
  {
    return true;
  }
  return false;
}
stacktype STTop(ST* ps)//返回栈顶元素
{
  assert(ps);
  return ps->data[ps->top];
}
void STDestory(ST* ps)//销毁栈
{
  assert(ps);
  free(ps->data);
  ps->data = NULL;
  ps->top = -1;
  ps->capacaity = 0;
}
//模拟队列类型的声明
typedef struct {
    ST stackpush;
    ST stackpop;
} MyQueue;
//队列的初始化
MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("obj malloc fail");
    }
    //一定要记得这里要初始化
    InitST(&obj->stackpush);
    InitST(&obj->stackpop);
    return obj;
}
void myQueuePush(MyQueue* obj, int x) {
    assert(obj);
    STPush(&obj->stackpush,x);
}
int myQueuePop(MyQueue* obj) {
     assert(obj);
     if(STEmpty(&obj->stackpop))//如果栈(stackpop模拟出栈)为空,则向栈(stackpush模拟入栈)要数据
     {
          while(!STEmpty(&obj->stackpush))
        {
            //将栈(stackpush模拟入队)的栈顶元素依次压入栈(stackpop模拟出栈)
            STPush(&obj->stackpop,STTop(&obj->stackpush));
            STPop(&obj->stackpush);
        }
     }
    int top=STTop(&obj->stackpop);//记录用来模拟出队列的栈的栈顶元素;
    STPop(&obj->stackpop);
    return top;
}
bool myQueueEmpty(MyQueue* obj) {
    if(STEmpty(&obj->stackpush)&&STEmpty(&obj->stackpop))//如果都为空,则为空栈
    {
        return true;
    }
    else 
    return false;
    //return STEmpty(&obj->stackpush)&&STEmpty(&obj->stackpop);
}
int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&obj->stackpop))//如果栈(stackpop模拟出栈)为空,则向栈(stackpush模拟入栈)要数据
     {
        while(!STEmpty(&obj->stackpush))
        {
            //将栈(stackpush模拟入队)的栈顶元素依次压入栈(stackpop模拟出栈)
            STPush(&obj->stackpop,STTop(&obj->stackpush));
            STPop(&obj->stackpush);
        }
    }
    int top=STTop(&obj->stackpop);//记录用来模拟出队列的栈的栈顶元素;
    return top;
    //return STTop(&obj->stackpop);
}
void myQueueFree(MyQueue* obj) {
    STDestory(&obj->stackpush);
    STDestory(&obj->stackpop);
    free(obj);
}


运行结果:


目录
相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
187 9
|
24天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
44 5
|
2月前
|
C语言
数组栈的实现(C语言描述)
本文介绍了如何在C语言中使用数组来实现栈的数据结构,包括栈的创建、入栈、出栈、获取栈顶元素、检查栈是否为空、获取栈的大小以及销毁栈等操作,并提供了相应的函数实现。
41 1
|
3月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
479 8
|
3月前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
512 3
|
6月前
|
C语言
C语言的栈帧
C语言的栈帧
|
20天前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
40 10
|
20天前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
42 9
|
20天前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
32 8
|
20天前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
41 6