当前位置:   article > 正文

栈和队列的图文讲解,小白易懂_栈的基本图形

栈的基本图形
  • 简述:

栈是限定仅在表尾进行插入和删除操作的线性表。

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

一.栈

1栈的基本概念

1.1栈的定义

我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(botton),不含任何的数据元素的栈称为空栈。栈又称为后进后出(Last In First Out)的线性表,简称LIFO结构。

栈的插入操作,叫进栈,也称为压栈、入栈。类似子弹入弹夹,如下图所示。

栈的删除操作,叫作出栈,也有的叫作弹栈。如同子弹出来,如下图所示。

1.2栈的实现

栈的实现一般可以使用 数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

栈的基本操作

ADT栈(stack)
Data
同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
InitStack(*S):初始化操作,建立一个空栈S。
DestroyStack(*S):若栈存在,则销毁它。ClearStack(*s):将栈清空。
StackEmpty(S):若栈为空,返回true,否则返回fa1se。
GetTop(S,*e):若栈存在且非空,用e返回S的栈顶元素。
Push(*S,e):若栈S存在,插入新元素e到栈s中并成为栈顶元素。
Pop(*S,*e):删除栈S中栈顶元素,并用e返回其值。
StackIength(S):返回栈S的元素个数。
endADT

2静态栈的实现

  1. // 下面是定长的静态栈的结构,实际中一般不实用,所以我们简单概括
  2. typedef int STDataType;//定义数据类型
  3. #define N 10
  4. typedef struct Stack
  5. {
  6. STDataType a[N];
  7. int top; // 栈顶
  8. }Stack;

2.1初始化栈

  1. void StackInit(Stack *ST)
  2. {
  3. ST->top = -1; //初始化栈顶指针,注意top=-1
  4. }

2,2判断栈是否为空

  1. bool StackEmpty(Stack *ST)
  2. {
  3. return ST->top == -1;
  4. }

2.3进栈

  1. void StackPush(Stack *ST,STDataType x)
  2. {
  3.     assert(ST->top!=N);
  4.     ST->top++;
  5.     ST->a[ST->top]=x;
  6. }

2.4出栈

  1. STDataType StackPop(Stack *ST)
  2. {
  3.     assert(ST->top>=0);
  4.     STDataType x=ST->a[ST->top];
  5.     ST->top--;
  6.     return x;
  7. }

2.5返回栈顶元素

  1. STDataType StackTop(Stack *ST)
  2. {
  3.     assert(!StackEmpty(ST));
  4.     return ST->a[ST->top];
  5. }

3.动态栈的实现

  1. // 支持动态增长的栈
  2. #include<assert.h>
  3. #include<stdbool.h>
  4. #include<stdio.h>
  5. #include<stdlib.h>
  6. //#define N 10
  7. //struct Stack
  8. //{
  9. // int a[N];
  10. // int top;
  11. //};
  12. typedef char STDataType;//定义数据类型
  13. typedef struct Stack
  14. {
  15. STDataType* a;
  16. int top;//栈顶数
  17. int capacity;//容量
  18. }ST;
  19. //初始化栈
  20. void STInit(ST* ps);
  21. //销毁栈
  22. void STDestroy(ST* ps);
  23. //压栈
  24. void STPush(ST* ps, STDataType x);
  25. //出栈
  26. void STPop(ST* ps);
  27. //返回栈的个数
  28. int STSize(ST* ps);
  29. //判断栈是否为空
  30. bool STEmpty(ST* ps);
  31. //返回栈顶元素
  32. STDataType STTop(ST* ps);
  33. //判断是否回文
  34. bool STMatch(ST* ps);

3.1动态代码的实现

  1. #include"Stack.h"
  2. void STInit(ST* ps)
  3. {
  4. assert(ps);
  5. ps->a = (STDataType*)malloc(sizeof(STDataType)*4);
  6. if (ps->a == NULL)
  7. {
  8. perror("malloc fail");
  9. return;
  10. }
  11. ps->top = 0;
  12. ps->capacity = 4;
  13. }
  14. void STDestroy(ST* ps)
  15. {
  16. assert(ps);
  17. free(ps->a);
  18. ps->a = NULL;
  19. ps->top = 0;//注意起点为0,压入时先赋值,再移动下标。
  20. ps->capacity = 0;
  21. }
  22. void STPush(ST* ps, STDataType x)
  23. {
  24. assert(ps);
  25. if (ps->top == ps->capacity)
  26. {
  27. STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType)*ps->capacity*2);
  28. if (tmp == NULL)
  29. {
  30. perror("realloc fail");
  31. return;
  32. }
  33. ps->capacity *= 2;
  34. ps->a = tmp;
  35. }
  36. ps->a[ps->top] = x;
  37. ps->top++;
  38. }
  39. void STPop(ST* ps)
  40. {
  41. assert(ps);
  42. assert(!STEmpty(ps));
  43. ps->top--;
  44. }
  45. int STSize(ST* ps)
  46. {
  47. assert(ps);
  48. return ps->top;
  49. }
  50. bool STEmpty(ST* ps)
  51. {
  52. assert(ps);
  53. return ps->top == 0;
  54. }
  55. STDataType STTop(ST* ps)
  56. {
  57. assert(ps);
  58. assert(!STEmpty(ps));
  59. return ps->a[ps->top - 1];//注意栈顶元素是ps->top的前一个
  60. }
  61. bool STMatch(ST* ps)
  62. {
  63. assert(ps);
  64. ST tmp;
  65. STInit(&tmp);
  66. while (STTop(ps) != '&')
  67. {
  68. STPush(&tmp, STTop(ps));
  69. STPop(ps);
  70. }
  71. STPop(ps);
  72. while (!STEmpty(ps))
  73. {
  74. if (STTop(&tmp) != STTop(ps))
  75. return false;
  76. STPop(ps);
  77. STPop(&tmp);
  78. }
  79. return true;
  80. }

二、队列

4.队列的基本概念

4.1队列的定义

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。

队列是一种先进先出FIFO(First In First Out)的线性表。

允许进行插入操作的一端称为队尾

允许进行删除操作的一端称为队头。

4.2队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

队列的基本操作

  1. //定义类型
  2. typedef char QDataType;
  3. //定义队列结点结构
  4. typedef struct QueueNode
  5. {
  6. struct QueueNode* next;
  7. QDataType data;
  8. }QNode;
  9. //定义队列的头指针和尾指针
  10. typedef struct Queue
  11. {
  12. QNode* head;
  13. QNode* tail;
  14. int size;
  15. }Queue;
  16. //初始化队列
  17. void QueueInit(Queue* pq);
  18. //销毁队列
  19. void QueueDestroy(Queue* pq);
  20. //入队
  21. void QueuePush(Queue* pq,QDataType x);
  22. //出队
  23. void QueuePop(Queue* pq);
  24. //返回队列的个数
  25. int QueueSize(Queue* pq);
  26. //检查队列是否为空
  27. bool QueueEmpty(Queue* pq);
  28. //返回头结点的数据
  29. QDataType QueueFront(Queue* pq);
  30. //返回尾结点的数据
  31. QDataType QueueBack(Queue* pq);
  32. //打印队列的全部元素
  33. void QueuePrint(Queue* pq);

5队列的链表实现

  1. #include"Queue.h"
  2. void QueueInit(Queue* pq)
  3. {
  4. assert(pq);
  5. pq->head = pq->tail = NULL;
  6. pq->size = 0;
  7. }
  8. void QueueDestroy(Queue* pq)
  9. {
  10. assert(pq);
  11. QNode* cur = pq->head;
  12. while (cur)//当前指针为空,则结束循环
  13. {
  14. QNode* next = cur->next;
  15. free(cur);
  16. cur = next;
  17. }
  18. pq->head = pq->tail = NULL;
  19. pq->size = 0;
  20. }
  21. void QueuePush(Queue* pq, QDataType x)
  22. {
  23. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  24. if (newnode == NULL)
  25. {
  26. perror("malloc fail");
  27. return;
  28. }
  29. newnode->data = x;
  30. newnode->next = NULL;
  31. if (pq->head == NULL )
  32. {
  33. assert(pq->tail == NULL);
  34. pq->head = pq->tail = newnode;
  35. }
  36. else
  37. {
  38. pq->tail->next = newnode;
  39. pq->tail = newnode;
  40. }
  41. pq->size++;//重点
  42. }
  43. void QueuePop(Queue* pq)
  44. {
  45. assert(pq);
  46. assert(pq->head != NULL);
  47. /*
  48. QNode* next = ps->head->next;
  49. free(pq->head);
  50. pq->head = next;
  51. if(pq->head == NULL)
  52. pq->tail = NULL;
  53. //可读性差
  54. */
  55. if (pq->head->next == NULL)
  56. {
  57. free(pq->head);
  58. pq->head = pq->tail = NULL;
  59. }
  60. else
  61. {
  62. QNode* next = pq->head->next;
  63. free(pq->head);
  64. pq->head = next;
  65. }
  66. pq->size--;
  67. }
  68. int QueueSize(Queue* pq)
  69. {
  70. assert(pq);
  71. return pq->size;
  72. }
  73. bool QueueEmpty(Queue* pq)
  74. {
  75. assert(pq);
  76. return pq->size == 0;
  77. }
  78. QDataType QueueFront(Queue* pq)
  79. {
  80. assert(pq);
  81. assert(!QueueEmpty(pq));
  82. return pq->head->data;
  83. }
  84. QDataType QueueBack(Queue* pq)
  85. {
  86. assert(pq);
  87. assert(!QueueEmpty(pq));
  88. return pq->tail->data;
  89. }
  90. void QueuePrint(Queue* pq)
  91. {
  92. assert(pq);
  93. QNode* cur = pq->head;
  94. while (cur)//当前指针为空,则结束循环
  95. {
  96. printf("%c -> ", cur->data);
  97. cur = cur->next;
  98. }
  99. printf("NULL\n");
  100. }

另外扩展了解一下,实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。

三.栈和队列面试题

括号匹配问题。 OJ链接
用队列实现栈。 OJ链接
用栈实现队列。 OJ链接
设计循环队列。 OJ链接

有兴趣的话可以试一下

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/557508
推荐阅读
相关标签
  

闽ICP备14008679号