用栈模拟实现队列(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);
}


运行结果:


目录
相关文章
|
24天前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
|
26天前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
151 3
|
4月前
|
C语言
C语言的栈帧
C语言的栈帧
|
4月前
|
C语言 C++
【数据结构】C语言实现:栈(Stack)与队列(Queue)
【数据结构】C语言实现:栈(Stack)与队列(Queue)
|
4月前
数据结构——栈(C语言版)
数据结构——栈(C语言版)
20 0
|
4月前
数据结构——队列(C语言版)
数据结构——队列(C语言版)
31 0
|
5月前
|
机器学习/深度学习 算法 编译器
【C语言】函数 ---- 函数的嵌套调用和链式访问、函数的声明和定义、变量的声明和定义、函数递归与迭代、递归时的栈溢出问题
【C语言】函数 ---- 函数的嵌套调用和链式访问、函数的声明和定义、变量的声明和定义、函数递归与迭代、递归时的栈溢出问题
105 0
|
C语言
C语言队列实现
一,简介 开发环境是VC6.0,实现了一个基于C语言的队列。 主要功能,入队、出队、显示当前队列元素。
119 0
|
23天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
26天前
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。