• 【C语言数据结构——————栈和队列4000字详解】


                             

    欢迎阅读新一期的c语言数据结构模块————栈和队列

    ✒️个人主页-_Joker_-

    🏷️专栏:C语言

    📜代码仓库:c_code

    🌹🌹欢迎大佬们的阅读和三连关注,顺着评论回访🌹🌹


    文章目录

      • 一、栈的概念       
        • 1.什么是栈
        • 2.栈的基本操作
      • 二、栈的实现
        • 1.定义栈的结构
        • 2.栈的初始化
        • 3.栈的判空
        • 4.入栈
        • 5.出栈
        • 6.获取栈顶元素
        • 7.栈的销毁
    • 队列
      • 一、队列的概念
        • 1.什么是队列
        • 2.队列的基本操作
      • 二、队列的实现
        • 1.定义队列的结构
        • 2.队列初始化
        • 3.队列判空
        • 4.入队
        • 5.出队
        • 6.获取队首元素
        • 7.队列的销毁


    一、栈的概念

    1.什么是栈

    栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

    栈顶(Top): 线性表允许进行插入删除的那一端。
    栈底(Bottom): 固定的,不允许进行插入和删除的另一端。
    空栈: 不含任何元素的空表。

    因为其后进先出(Last In First Out)的特性,栈又称为的线性表,简称LIFO结构


    2.栈的基本操作

    栈的基本操作通常都有以下几种:

    • InitStack(&Stack):初始化一个空栈S。
    • StackEmpty(&Stack):判断一个栈是否为空,若栈为空则返回true,否则返回false。
    • StackPush(&Stack, x):进栈(栈的插入操作),若栈S未满,则将x加入使之成为新栈顶。
    • StackPop(&Stack):出栈(栈的删除操作),若栈S非空,则返回一个提示.
    • GetTop(&Stack):读栈顶元素。
    • DestroyStack(&Stack):栈销毁,并释放S占用的存储空间(“&”表示引用调用)。

    二、栈的实现

    1.定义栈的结构

    栈又分为顺序栈和链式栈,这里我们以顺序栈为例

    首先想要实现一个栈,我们需要了解如何创建一个栈的结构,这里我们可以用结构体来定义,有两种方式:

    1. #define N 10//定义栈的大小
    2. struct Stack
    3. {
    4. int a[N];
    5. int top;//栈顶
    6. };

    1. typedef int STDataType;
    2. typedef struct Stack
    3. {
    4. STDataType* a;//定义一个栈
    5. int top;//栈顶
    6. int capacity;//栈的大小
    7. }ST;

    第一种结构是用一个宏定义常量定义的栈的大小,这种用静态开辟的空间存在一些瑕疵,如果栈的空间大小太小需要成倍的扩容,很容易造成空间的浪费,所以我们优先采用方法②。

    这种方法的好处在于我们可以动态开辟空间,如果空间不够就多开一个空间,这样就可以避免空间的浪费。


    2.栈的初始化

    1. void InitStack(ST* ps)
    2. {
    3. assert(ps);//断言
    4. ps->a = NULL;//将指针置为空
    5. ps->capacity = 0;//初始化大小
    6. ps->top = 0;
    7. }

    3.栈的判空

    1. bool StackEmpty(ST* ps)
    2. {
    3. assert(ps);//断言
    4. return ps->top == 0;//栈顶为0则为空
    5. }

    4.入栈

    入栈的具体流程如图

    入栈首先判断空间大小,若已满则需要扩容,然后从栈底向上逐个插入

    入栈操作如下

    1. void StackPush(ST* ps, STDataType x)
    2. {
    3. assert(ps);//断言
    4. if (ps->top == ps->capacity)
    5. {
    6. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    7. STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
    8. //扩容
    9. if (tmp == NULL)//判断空间是否开辟成功
    10. {
    11. perror("realloc fail");
    12. exit(-1);
    13. }
    14. ps->a = tmp;
    15. ps->capacity = newCapacity;
    16. }
    17. ps->a[ps->top] = x;//插入元素
    18. ps->top++;//栈顶移动
    19. }

    5.出栈

    出栈操作如图

    出栈首先判断是否为空,若为空则返回一个提示,若不为空则只需要直接将栈顶向下移动即可达到出栈的效果。

    出栈操作如下;

    1. void StackPop(ST* ps)
    2. {
    3. assert(ps);//断言
    4. assert(ps->top > 0);//判断空
    5. --ps->top;//栈顶移动
    6. }

    6.获取栈顶元素

    这里需要注意top的位置,如果top的指向是栈顶元素的话则只需要return a[ps->top]即可,由于我这里的top是指向栈顶元素的下一个位置,所以需要top-1才可以获取到栈顶元素.

    1. STDataType StackTop(ST* ps)
    2. {
    3. assert(ps);
    4. assert(ps->top > 0);//判断为空
    5. return ps->a[ps->top - 1];//返回栈顶元素
    6. }

    7.栈的销毁

    1. void StackDestroy(ST* ps)
    2. {
    3. assert(ps);
    4. free(ps->a);//释放栈的空间
    5. ps->a = NULL;//将指针置空,防止野指针产生
    6. ps->top = ps->capacity = 0;
    7. }

    队列

    一.队列的概念

    1.什么是队列

    队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

    队首(front): 线性表允许进行插入删除的那一端。
    队尾(rear)固定的,不允许进行插入和删除的另一端。
    空队列: 不含任何元素的空表。

    因为其先进先出(First In First Out)的特性,队列又称为的线性表,简称FIFO结构


    2.队列的基本操作

    • QueueInit(&Q):初始化队列,构造一个空队列Q。
    • QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。
    • QueuePush(&Q, x):入队,若队列Q未满,将x加入,使之成为新的队尾。
    • QueuePop(&Q):出队,若队列Q非空,删除队头元素。
    • QueueFront(&Q):读队头元素。
    • QueueDestroy(&Q): 队列销毁。

    二.队列的实现

    队列同样拥有两种实现方式(顺序结构和链式结构),但是用顺序结构实现队列在出列的情况比较复杂,所以这里我们以链式结构来实现队列

    1.定义队列的结构

    和栈类似,队列的结构可以这样定义

    1. typedef int QDataType;
    2. typedef struct QueueNode//队列节点
    3. {
    4. struct QueueNode* next;
    5. QDataType data;
    6. }QNode;
    7. typedef struct Queue//队列结构
    8. {
    9. QNode* head;//队首
    10. QNode* tail;//队尾
    11. int size;
    12. }Que;

    2.队列初始化

    1. void QueueInit(Que* pq)
    2. {
    3. assert(pq);//断言
    4. pq->head = pq->tail = NULL;//头尾指针置空
    5. pq->size = 0;//大小初始化
    6. }

    3.队列判空

    1. bool QueueEmpty(Que* pq)
    2. {
    3. assert(pq);//断言
    4. return pq->head == NULL;//头指针为空则为空
    5. }

    4.入队

    入队操作如图

    入队新开一个节点,将元素插入新的节点,然后判断尾指针是否指向空,若为空则将头尾指针指向新的节点,若不为空则将新的节点作为队尾。

    入队实现:

    1. void QueuePush(Que* pq, QDataType x)
    2. {
    3. assert(pq);//断言
    4. QNode* newnode = (QNode*)malloc(sizeof(QNode));//开一个新节点
    5. if (newnode == NULL)
    6. {
    7. perror("malloc fail");
    8. exit(-1);
    9. }
    10. newnode->data = x;//新节点赋值
    11. newnode->next = NULL;
    12. if (pq->tail == NULL)//空队列
    13. {
    14. pq->head = pq->tail = newnode;
    15. }
    16. else
    17. {
    18. pq->tail->next = newnode;
    19. pq->tail = newnode;
    20. }
    21. pq->size++;
    22. }

    5.出队

    出队操作和入队操作类似,出队首先判空,若队列为空则返回一个提示,若不为空需要将队首节点指向下一个节点并释放第一个节点。若队首的下一个元素为空,说明改队列只有一个节点,所以需要将头尾指针置空防止野指针的产生。

    出队操作如下

    1. void QueuePop(Que* pq)
    2. {
    3. assert(pq);
    4. assert(!QueueEmpty(pq));//判空
    5. if (pq->head->next == NULL)//判断队首下一个节点是否为空
    6. {
    7. free(pq->head);
    8. pq->head = pq->tail = NULL;
    9. }
    10. else
    11. {
    12. QNode* next = pq->head->next;//新开一个节点并将头指针下一个节点给新节点
    13. free(pq->head);//释放队首
    14. pq->head = next;//将新开的节点赋给新队首
    15. }
    16. pq->size--;//队列大小-1
    17. }

    6.读取队首元素

    1. QDataType QueueFront(Que* pq)
    2. {
    3. assert(pq);
    4. assert(!QueueEmpty(pq));//判空
    5. return pq->head->data;//取队首元素
    6. }

    7.队列销毁

    1. void QueueDestroy(Que* pq)
    2. {
    3. assert(pq);
    4. QNode* cur = pq->head;//创建一个节点存储队首
    5. while (cur)//
    6. {
    7. QNode* next = cur->next;//创建一个中间节点
    8. free(cur);//从队首一个一个删除
    9. cur = next;
    10. }
    11. pq->head = pq->tail = NULL;//删完所有节点将指针置空
    12. pq->size = 0;//初始化大小
    13. }


    以上就是栈和队列的基本概念和基础操作实现,如果文章存在错误请在评论区留言,最后别忘了三连支持一下,顺着评论回访🌹🌹
  • 相关阅读:
    关于Java面试:GC机制的一些总结
    《可供方案开发》口算训练机/数学宝/儿童口算宝/智能数学宝 LCD液晶显示驱动IC-VK0256B,原厂技术支持
    c++ 类中隐藏的六个(c11之后 八个)默认函数
    Kafka-exporter监控消费速度与生产速度差异规则
    本地部署腾讯的tmagic-editor低代码
    【Rust】自定义数据类型—结构体——Rust语言基础13
    【新知实验室 认识TRTC+四步跑通音视频demo】
    什么是实时流引擎?
    element-ui中表格树类型数据的显示
    霍夫hough变换直线检测浅显理解
  • 原文地址:https://blog.csdn.net/2302_76390850/article/details/133468489