千家信息网

C语言数据结构的栈和队列详解

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章主要介绍"C语言数据结构的栈和队列详解",在日常操作中,相信很多人在C语言数据结构的栈和队列详解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"C语言数据结构的栈
千家信息网最后更新 2026年10月31日C语言数据结构的栈和队列详解

这篇文章主要介绍"C语言数据结构的栈和队列详解",在日常操作中,相信很多人在C语言数据结构的栈和队列详解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"C语言数据结构的栈和队列详解"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

目录
  • 栈

    • 数组实现

    • 标题全部代码

      • Stack_array.c

      • Stack_array.h

      • 初始化数组栈

      • 满栈后扩容

      • 是否为空栈

      • 压栈和退栈

  • 链表实现

    • stack_chain.h

      • stack_chain.c

        • 整个压栈流程

          • 整个弹栈流程

            • 出栈情况

            • 队列

              • 队列的实现

                • queue_chain.h

                • queue_chain.c

              • 一个结构体类型用于维护这个队列

                • 概念流程图

                  • 入队列的实现

                    • 出队列的实现

                      • 是否空队

                      栈

                      栈是一种以后进先出为顺序对对象进行添加或删除的数据结构
                      对栈进行形象记忆就像是桌子上的一堆书或一堆盘。对盘子取或者存盘子,都只能对最上面的书或者盘子进行操作。

                      对于栈而言,只有弹栈才能获取其数据。
                      当我们用C语言实现栈这个数据结构。
                      其实有三种方法实现

                      1,数组

                      2,单链表

                      3,双向链表

                      但是,对于双向链表,实现栈而言过于复杂。
                      可以选择数组或者单链表。

                      数组实现

                      标题全部代码

                      Stack_array.c
                      #include "Stack_array.h"void InitStack(STstack* st)//栈的初始化{        st->top = 0;        st->arr = (STData*)malloc(CAP*sizeof(STData));        st->capacity = CAP;}void StackPush(STstack* st, STData n)//元素入栈{        if (st->top == st->capacity)//判断是否需要扩容        {                StackExpansion(st);        }        st->arr[st->top++] = n;}STData StackPop(STstack* st)//元素退栈{        assert(st);        assert(!StackEmpty(st));//判断是否为空栈        return st->arr[--st->top];}int StackEmpty(STstack* st)//判断栈是否为空{        if (st->top == 0)                return 1;        return 0;}void StackDestory(STstack* st)//销毁栈,防止内存泄漏{        free(st->arr);        st->arr = NULL;}void StackExpansion(STstack* st)//扩容{        STData* tmp = (STData*)realloc((STData*)st->arr, sizeof(STData) * (st->capacity) * 2);        if (tmp == NULL)        {                printf("Exparsion Error\n");                exit(-1);        }        st->arr = tmp;        st->capacity *= 2;}void StackPrint(STstack* st)//打印栈的元素,但前提是要退栈才能得到元素{        while(st->top)        {                STData ret = StackPop(st);                printf("%d ", ret);        }}
                      Stack_array.h
                      #pragma once#define _CRT_SECURE_NO_WARNINGS#include #include #include #define CAP 4typedef int STData;typedef struct Stack//结构体用于维护栈{        int top;//栈顶标记        STData* arr;//栈的指针        int capacity;//栈的容量}STstack;void InitStack(STstack* st);//栈的初始化void StackPush(STstack* st, STData n);//元素入栈STData StackPop(STstack* st);//元素退栈void StackExpansion(STstack* st);//扩容int StackEmpty(STstack* st);//判断栈是否为空void StackDestory(STstack* st);//销毁栈,防止内存泄漏void StackPrint(STstack* st);//打印栈的元素,但前提是要退栈才能得到元素

                      对于数组实现而言。创建一个结构体用于维护整个栈。而其中有一个用于链接创建的数组。

                      typedef int STData;typedef struct Stack//结构体用于维护栈{        int top;//栈顶标记        STData* arr;//栈的指针        int capacity;//栈的容量}STstack;

                      作为数组栈,需要一个动态的数组。则这就需要一个Capacity作为衡量是否需要扩容的标准。而top需要作为入栈元素的位置。
                      当top的值等于Capacity时就意味着栈已经满了。因为数组是从0开始的

                      初始化数组栈

                      在初始化时,要先动态开辟一个数组空间,且,未压栈压入数据元素,其top要设为0.要保证当需要压栈时有明确指定的空间。同时,top的位置要为最后压入数据的下一个下标。

                      void InitStack(STstack* st)//栈的初始化{        st->top = 0;        st->arr = (STData*)malloc(CAP*sizeof(STData));        st->capacity = CAP;}
                      满栈后扩容

                      其Capacity要作为判断是否满栈的标准。且,满栈后要进行扩容(因为是动态数组)。

                      void StackExpansion(STstack* st)//扩容{        STData* tmp = (STData*)realloc((STData*)st->arr, sizeof(STData) * (st->capacity) * 2);        if (tmp == NULL)        {                printf("Exparsion Error\n");                exit(-1);        }        st->arr = tmp;        st->capacity *= 2;}

                      同时,还要每次更改栈的容量,为下一次是否满栈作为标准。

                      是否为空栈
                      int StackEmpty(STstack* st)//判断栈是否为空{        if (st->top == 0)                return 1;        return 0;}

                      其是否为空。也就是top的位置在数组的0下标位。

                      压栈和退栈
                      void StackPush(STstack* st, STData n)//元素入栈{        if (st->top == st->capacity)//判断是否需要扩容        {                StackExpansion(st);        }        st->arr[st->top++] = n;}STData StackPop(STstack* st)//元素退栈{        assert(st);        assert(!StackEmpty(st));//判断是否为空栈        return st->arr[--st->top];}

                      压栈
                      每次压栈,都需要判断是否满栈,并决定是否扩容。
                      同时,当在原先top位置的数位置进行赋值。并之后要将top向后移动一个位置。保证下一次压栈。

                      退栈
                      退栈返回top的上一个位置的元素。同时top向前移动一个位置,不需要free,下次压栈会自动覆盖。

                      链表实现

                      stack_chain.h

                      #include #include #define N 3typedef struct stackele{        int n;        int* point;}sta;sta* top;void initstack(sta* a);//初始化栈void pushstack(sta* a,int num);//入栈//void printstack(sta* a);//打印栈//void fullstack(sta* a);//检查是否满栈的情况void emptystack(sta* a);//检查是否空栈的情况int popstack(sta*a);//出栈

                      stack_chain.c

                      #include "stack_chain.h"void initstack(sta* a)//初始化栈{        top= NULL;}void pushstack(sta* a, int num)//入栈{        sta* p = (sta*)malloc(sizeof(sta));        p->n = num;//新节点赋值        p->point = top;        top = p;}int popstack(sta* a)//出栈{        emptystack(a);//检查是否空栈的情况        int date;        sta* des = top;        top = top->point;        date = des->n;        free(des);        des = NULL;        return date;}void emptystack(sta* a)//检查是否空栈的情况{        if (top == NULL)        {                printf("Stack empty");                exit(0);        }}

                      对于链表实现栈而言,和数组其实差不多。只不够,每次压栈都需要重新动态开辟一个新节点,并且链入栈中。但是,这并不是普通的直接链入。而是需要头插入栈。

                      这样头插入栈,可以方便退栈的时候,可以找到上一个元素。而压栈是不需要什么顺序。每一个压栈节点就是top节点。

                      整个压栈流程

                      void pushstack(sta* a, int num)//入栈{        sta* p = (sta*)malloc(sizeof(sta));        p->n = num;//新节点赋值        p->point = top;        top = p;}

                      整个弹栈流程

                      int popstack(sta* a)//出栈{        emptystack(a);//检查是否空栈的情况        int date;        sta* des = top;        top = top->point;        date = des->n;        free(des);        des = NULL;        return date;}

                      出栈情况

                      尤其要把握一个条件:空栈
                      由于不是数组,且链式结构的特性,是不需要扩容的。即不需要判断满栈的情况。
                      只考虑空栈的条件

                      void emptystack(sta* a)//检查是否空栈的情况{        if (top == NULL)        {                printf("Stack empty");                exit(0);        }}

                      这里空栈的条件是top指针指向NULL时也就是

                      为什么呢?
                      因为每次弹栈的时候,都会free掉top指向的空间然后让top指向下一个节点。就这样不断移动。但是我设计初始化的时候是top= NULL;而且每次压栈都是p->point = top;这就会有一个标准来限定空栈的情况。

                      对于栈而言,其更像是一个递归的具象化。

                      队列

                      这种数据结构就像是银行柜台的取号机,
                      先取号的先去柜台。

                      始终满足先入先出的概念

                      队列的实现

                      queue_chain.h
                      #define _CRT_SECURE_NO_WARNINGS#include #include #include typedef int QUData;typedef struct queue{        QUData data;        struct queue* next;}queue;typedef struct Queue//结构体用于维护队列{        queue* Dequeue;//队头指针        queue* Enqueue;//队尾指针}QUqueue;void InitQueue(QUqueue* qu);//栈的初始化void QueuePush(QUqueue* qu, QUData n);//元素入队QUData QueuePop(QUqueue* qu);//元素出队int QueueEmpty(QUqueue* qu);//判断队列是否为空void QueueDestory(QUqueue* qu);//销毁队,防止内存泄漏void QueuePrint(QUqueue* qu);//打印队列中的元素,但前提是要出队才能得到元素
                      queue_chain.c
                      #include "queue_chain.h"void InitQueue(QUqueue* qu)//队列的初始化{        qu->Dequeue = qu->Enqueue = NULL;}void QueuePush(QUqueue* qu, QUData n)//元素入队{        queue* newcell = (QUData*)malloc(sizeof(QUData));        newcell->data = n;        newcell->next = NULL;        if (qu->Dequeue == NULL)        {                qu->Enqueue = qu->Dequeue = newcell;        }        else        {                qu->Enqueue->next = newcell;                qu->Enqueue = newcell;        }}QUData QueuePop(QUqueue* qu)//元素出队{        if (QueueEmpty(qu))        {                printf("Queue Is Empty");                exit(-1);        }        QUData ret = qu->Dequeue->data;        qu->Dequeue = qu->Dequeue->next;        return ret;}int QueueEmpty(QUqueue* qu)//判断队列是否为空{        if (qu->Dequeue == qu->Enqueue)                return 1;        return 0;}void QueueDestory(QUqueue* qu)//销毁队,防止内存泄漏{        queue* cur = qu->Dequeue;        while (cur)        {                queue* pnext = cur->next;                free(cur);                cur = pnext;        }        qu->Dequeue = qu->Enqueue = NULL;}void QueuePrint(QUqueue* qu)//打印队列中的元素,但前提是要出队才能得到元素{        queue* cur = qu->Dequeue;        while (cur)        {                printf("%d ", cur->data);                cur = cur->next;        }}

                      队 毕竟是先入先出的数据结构。
                      所以要两个指针,
                      qu->Dequeue 指向队头,
                      qu->Enqueue 指向队尾,
                      不然每次都去找队尾是相当浪费时间的。

                      一个结构体类型用于维护这个队列

                      typedef int QUData;typedef struct queue//描述每个队的元素{        QUData data;        struct queue* next;}queue;typedef struct Queue//结构体用于维护队列{        queue* Dequeue;//队头指针        queue* Enqueue;//队尾指针}QUqueue;

                      队头指针负责出队,
                      队尾指针负责入队。

                      概念流程图

                      入队

                      入队列的实现

                      void QueuePush(QUqueue* qu, QUData n)//元素入队{        queue* newcell = (QUData*)malloc(sizeof(QUData));        newcell->data = n;        newcell->next = NULL;        if (qu->Dequeue == NULL)        {                qu->Enqueue = qu->Dequeue = newcell;        }        else        {                qu->Enqueue->next = newcell;                qu->Enqueue = newcell;        }}

                      **当然,入队列在刚开始的时候,头尾指针还是一起指向NULL。
                      当入第一个元素时,那个元素即是第一个元素也是最后一个元素。要独立判断。**这是一个特殊情况。

                      出队

                      出队列的实现

                      QUData QueuePop(QUqueue* qu)//元素出队{        if (QueueEmpty(qu))        {                printf("Queue Is Empty");                exit(-1);        }        QUData ret = qu->Dequeue->data;        qu->Dequeue = qu->Dequeue->next;        return ret;}

                      但是每次出队列都需要判断是否为空队。如果是空队还继续出队会相当于NULL->next ,这是直接报错的。

                      所以还要一个函数判断是否空队。

                      是否空队

                      int QueueEmpty(QUqueue* qu)//判断队列是否为空{        if (qu->Dequeue == qu->Enqueue)                return 1;        return 0;}

                      空队就是相当于回到了初始化的情形

                      qu->Dequeue = qu->Enqueue = NULL;

                      也就是两者都指向同一处,也就是NULL。

                      到此,关于"C语言数据结构的栈和队列详解"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

                      元素 队列 结构 数组 数据 情况 指针 数据结构 位置 指向 流程 节点 检查 语言 也就是 内存 前提 动态 同时 时候 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海挚品互联网科技有限公司 喔噻互联网科技有限公司 互联网是第几次科技革命的成果 美国互联网保险保险科技 圆梦互联网科技 西安互联网科技 贷财互联网科技 新浪科技互联网 互联网 视角下的科技创新 广州善班互联网科技 长亮科技 互联网金融 广州慧亚互联网科技怎么样 汽车互联网创新科技园 互联网对科技的发展 和信科技工业互联网 翼展科技 首家互联网医院 烟台灵鸽互联网科技有限公司 滨湖区互联网智能科技产品有哪些 全球科技与互联网公司市值变化 保山浩联互联网科技有限公司 互联网科技集团 上海喔噻互联网科技 唐信互联网科技 大连 宁波青枫互联网科技有限公司 昊天互联网科技有限公司 中国互联网公司排名锤子科技 神州科技互联网有限公司 科技信息时代互联网发展 上海旺乐尼互联网科技有限公司 株洲百竞科技的互联网营销顾问
                      0