当前位置:   article > 正文

【数据结构】栈和队列_队列插入

队列插入

目录

数据结构之栈和队列::

                          1.栈的实现

                        栈的初始化

                        ​栈的销毁

                        栈的插入

​                        栈的删除

                        取栈顶数据

​                        栈的判空

                        栈的大小

                        ​2.队列的实现

                        队列的初始化

                        队列的销毁

                        队列的插入

                        队列的删除

                       取队头数据

                       取队尾数据

                       队列的判空

                       队列的大小

                        3.栈和队列面试题 


                                      

数据结构之栈和队列::

1.栈的实现

栈的概念及结构:
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作,进行数据插入和删除的一端称为栈顶,另一端称为栈底,栈中的数据元素遵守先进后出LIFO(Last in First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈,出数据也在栈顶。

 

 栈的实现:
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些,因为数组在尾上插入数据的代价比较小。
注:如果用链表实现,建议头部做栈顶,尾部做栈底。
注:栈的后进先出指的是同时在栈里面。

  

 Stack.h

  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<assert.h>
  6. typedef int STDataType;
  7. typedef struct Stack
  8. {
  9. STDataType * a;
  10. int top;
  11. int capacity;
  12. }ST;
  13. void StackInit(ST* ps);
  14. void StackDestory(ST* ps);
  15. void StackPush(ST* ps, STDataType x);
  16. void StackPop(ST* ps);
  17. bool StackEmpty(ST* ps);
  18. int StackSize(ST* ps);
  19. //访问栈顶数据
  20. STDataType StackTop(ST* ps);

 Stack.c

  1. #include"Stack.h"
  2. void StackInit(ST* ps)
  3. {
  4. assert(ps);
  5. ps->a = NULL;
  6. ps->top = ps->capacity = 0;
  7. }
  8. bool StackEmpty(ST* ps)
  9. {
  10. assert(ps);
  11. return ps->top == 0;
  12. }
  13. void StackDestory(ST* ps)
  14. {
  15. assert(ps);
  16. free(ps->a);
  17. ps->a = NULL;
  18. ps->capacity = ps->top = 0;
  19. }
  20. //数据结构建议不要直接访问结构体数据,一定要通过函数接口访问
  21. //解耦:高内聚,低耦合
  22. void StackPush(ST* ps, STDataType x)
  23. {
  24. assert(ps);
  25. if (ps->top == ps->capacity)
  26. {
  27. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  28. STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity * sizeof(STDataType));
  29. if (tmp == NULL)
  30. {
  31. perror("realloc fail");
  32. exit(-1);
  33. }
  34. ps->a = tmp;
  35. ps->capacity = newCapacity;
  36. }
  37. ps->a[ps->top] = x;
  38. ps->top++;
  39. }
  40. void StackPop(ST* ps)
  41. {
  42. assert(ps);
  43. assert(!StackEmpty(ps));
  44. ps->top--;
  45. }
  46. STDataType StackTop(ST* ps)
  47. {
  48. assert(ps);
  49. //为空不能访问栈顶元素
  50. assert(!StackEmpty(ps));
  51. return ps->a[ps->top - 1];
  52. }
  53. int StackSize(ST* ps)
  54. {
  55. assert(ps);
  56. return ps->top;
  57. }

栈的初始化

  1. void StackInit(ST* ps)
  2. {
  3. assert(ps);
  4. ps->a = NULL;
  5. ps->top = ps->capacity = 0;
  6. }

栈的销毁:

  1. void StackDestory(ST* ps)
  2. {
  3. assert(ps);
  4. free(ps->a);
  5. ps->a = NULL;
  6. ps->capacity = ps->top = 0;
  7. }

栈的插入:

  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, newCapacity * sizeof(STDataType));
  8. if (tmp == NULL)
  9. {
  10. perror("realloc fail");
  11. exit(-1);
  12. }
  13. ps->a = tmp;
  14. ps->capacity = newCapacity;
  15. }
  16. ps->a[ps->top] = x;
  17. ps->top++;
  18. }

栈的删除:

  1. void StackPop(ST* ps)
  2. {
  3. assert(ps);
  4. assert(!StackEmpty(ps));
  5. ps->top--;
  6. }

取栈顶数据:

  1. STDataType StackTop(ST* ps)
  2. {
  3. assert(ps);
  4. //为空不能访问栈顶元素
  5. assert(!StackEmpty(ps));
  6. return ps->a[ps->top - 1];
  7. }

栈的判空:

  1. bool StackEmpty(ST* ps)
  2. {
  3. assert(ps);
  4. return ps->top == 0;
  5. }

栈的大小:

  1. int StackSize(ST* ps)
  2. {
  3. assert(ps);
  4. return ps->top;
  5. }

2.队列的实现

队列的概念及结构:
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的原则。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一端称为队头。 


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

Queue.h

  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. #include<stdbool.h>
  6. typedef int QDataType;
  7. typedef struct QueueNode
  8. {
  9. struct QueueNode* next;
  10. QDataType data;
  11. }QNode;
  12. //第三种不用二级指针的方式 封装成结构体
  13. typedef struct Queue
  14. {
  15. QNode* head;
  16. QNode* tail;
  17. int size;
  18. }Queue;
  19. void QueueInit(Queue* pq);
  20. void QueueDestory(Queue* pq);
  21. void QueuePush(Queue* pq, QDataType x);
  22. void QueuePop(Queue* pq);
  23. //取队列头部数据
  24. QDataType QueueFront(Queue* pq);
  25. //取队列尾部数据
  26. QDataType QueueBack(Queue* pq);
  27. bool QueueEmpty(Queue* pq);
  28. int QueueSize(Queue* pq);

Queue.c

  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. bool QueueEmpty(Queue* pq)
  9. {
  10. assert(pq);
  11. return pq->head == NULL && pq->tail == NULL;
  12. }
  13. void QueueDestory(Queue* pq)
  14. {
  15. assert(pq);
  16. QNode* cur = pq->head;
  17. while (cur)
  18. {
  19. QNode* del = cur;
  20. cur = cur->next;
  21. free(del);
  22. }
  23. pq->head = pq->tail = NULL;
  24. pq->size = 0;
  25. }
  26. void QueuePush(Queue* pq, QDataType x)
  27. {
  28. assert(pq);
  29. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  30. if (newnode == NULL)
  31. {
  32. perror("malloc fail");
  33. exit(-1);
  34. }
  35. else
  36. {
  37. newnode->data = x;
  38. newnode->next = NULL;
  39. }
  40. if (pq->tail == NULL)
  41. {
  42. pq->head = pq->tail = newnode;
  43. }
  44. else
  45. {
  46. pq->tail->next = newnode;
  47. pq->tail = newnode;
  48. }
  49. pq->size++;
  50. }
  51. void QueuePop(Queue* pq)
  52. {
  53. assert(pq);
  54. assert(!QueueEmpty(pq));
  55. if (pq->head->next == NULL)
  56. {
  57. free(pq->head);
  58. pq->head = pq->tail = NULL;
  59. }
  60. else
  61. {
  62. QNode* del = pq->head;
  63. pq->head = pq->head->next;
  64. free(del);
  65. del = NULL;
  66. }
  67. pq->size--;
  68. }
  69. //取队列头部数据
  70. QDataType QueueFront(Queue* pq)
  71. {
  72. assert(pq);
  73. assert(!QueueEmpty(pq));
  74. return pq->head->data;
  75. }
  76. //取队列尾部数据
  77. QDataType QueueBack(Queue* pq)
  78. {
  79. assert(pq);
  80. assert(!QueueEmpty(pq));
  81. return pq->tail->data;
  82. }
  83. int QueueSize(Queue* pq)
  84. {
  85. assert(pq);
  86. /*QNode* cur = pq->head;
  87. int n = 0;
  88. while (cur)
  89. {
  90. n++;
  91. cur = cur->next;
  92. }
  93. return n;*/
  94. return pq->size;
  95. }

队列的初始化:

  1. void QueueInit(Queue* pq)
  2. {
  3. assert(pq);
  4. pq->head = pq->tail = NULL;
  5. pq->size = 0;
  6. }

队列的销毁:

  1. void QueueDestory(Queue* pq)
  2. {
  3. assert(pq);
  4. QNode* cur = pq->head;
  5. while (cur)
  6. {
  7. QNode* del = cur;
  8. cur = cur->next;
  9. free(del);
  10. }
  11. pq->head = pq->tail = NULL;
  12. pq->size = 0;
  13. }

队列的插入:

  1. void QueuePush(Queue* 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. else
  11. {
  12. newnode->data = x;
  13. newnode->next = NULL;
  14. }
  15. if (pq->tail == NULL)
  16. {
  17. pq->head = pq->tail = newnode;
  18. }
  19. else
  20. {
  21. pq->tail->next = newnode;
  22. pq->tail = newnode;
  23. }
  24. pq->size++;
  25. }

 队列的删除:

  1. void QueuePop(Queue* 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* del = pq->head;
  13. pq->head = pq->head->next;
  14. free(del);
  15. del = NULL;
  16. }
  17. pq->size--;
  18. }

取队头数据:

  1. //取队列头部数据
  2. QDataType QueueFront(Queue* pq)
  3. {
  4. assert(pq);
  5. assert(!QueueEmpty(pq));
  6. return pq->head->data;
  7. }

取队尾数据:

  1. //取队列尾部数据
  2. QDataType QueueBack(Queue* pq)
  3. {
  4. assert(pq);
  5. assert(!QueueEmpty(pq));
  6. return pq->tail->data;
  7. }

队列的判空:

  1. bool QueueEmpty(Queue* pq)
  2. {
  3. assert(pq);
  4. return pq->head == NULL && pq->tail == NULL;
  5. }

队列的大小:

  1. int QueueSize(Queue* pq)
  2. {
  3. assert(pq);
  4. /*QNode* cur = pq->head;
  5. int n = 0;
  6. while (cur)
  7. {
  8. n++;
  9. cur = cur->next;
  10. }
  11. return n;*/
  12. return pq->size;
  13. }

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

  

3.栈和队列面试题 

1.括号匹配问题

  1. //有效的括号
  2. //将上面的栈拷贝下来
  3. //将栈typedef的数据类型改为char
  4. bool isValid(char* s)
  5. {
  6. ST st;
  7. StackInit(&st);
  8. while (*s)
  9. {
  10. if (*s == '{' || *s == '[' || *s == '(')
  11. {
  12. StackPush(&st, *s);
  13. }
  14. else
  15. {
  16. //取到右括号时 栈为空 说明前面左括号数量不匹配
  17. if (StackEmpty(&st))
  18. {
  19. StackDestory(&st);
  20. return false;
  21. }
  22. char top = StackTop(&st);
  23. StackPop(&st);
  24. if ((*s == '}' && top != '{')
  25. || (*s == ']' && top != '[')
  26. || (*s == '(' && top != ')'))
  27. {
  28. StackDestory(&st);
  29. return false;
  30. }
  31. }
  32. s++;
  33. }
  34. //栈不为空 说明数量不匹配
  35. bool flag = StackEmpty(&st);
  36. StackDestory(&st);
  37. return flag;
  38. }

2.用队列实现栈

  1. //用队列实现栈
  2. //用两个队列实现一个后入先出的栈
  3. //注:越界的检查是一种抽查,一般读时不会报错,写的时候要根据编译器的严格程度
  4. typedef struct
  5. {
  6. Queue q1;
  7. Queue q2;
  8. }MyStack;
  9. MyStack* myStackCreate()
  10. {
  11. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
  12. QueueInit(&obj->q1);
  13. QueueInit(&obj->q2);
  14. return obj;
  15. }
  16. void myStackPush(MyStack* obj, int x)
  17. {
  18. if (!QueueEmpty(&obj->q1))
  19. {
  20. QueuePush(&obj->q1, x);
  21. }
  22. else
  23. {
  24. QueuePush(&obj->q2, x);
  25. }
  26. }
  27. int myStackTop(MyStack* obj)
  28. {
  29. if (!QueueEmpty(&obj->q1))
  30. {
  31. return QueueBack(&obj->q1);
  32. }
  33. else
  34. {
  35. return QueueBack(&obj->q2);
  36. }
  37. }
  38. int myStackPop(MyStack* obj)
  39. {
  40. Queue* empty = &obj->q1;
  41. Queue* nonEmpty = &obj->q2;
  42. if (!QueueEmpty(&obj->q1))
  43. {
  44. empty = &obj->q2;
  45. nonEmpty = &obj->q1;
  46. }
  47. //非空队列前N-1个导入空队列 剩下一个就是栈顶元素
  48. while (QueueSize(nonEmpty) > 1)
  49. {
  50. QueuePush(empty, QueueFront(nonEmpty));
  51. QueuePop(nonEmpty);
  52. }
  53. //返回要删除的栈顶元素
  54. int top = QueueFront(nonEmpty);
  55. QueuePop(nonEmpty);
  56. return top;
  57. }
  58. bool myStackEmpty(MyStack* obj)
  59. {
  60. return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
  61. }
  62. void myStackFree(MyStack* obj)
  63. {
  64. QueueDestory(&obj->q1);
  65. QueueDestory(&obj->q2);
  66. free(obj);
  67. }

3.用栈实现队列

  1. //用栈实现队列
  2. typedef struct
  3. {
  4. ST pushST;
  5. ST popST;
  6. }MyQueue;
  7. MyQueue* myQueueCreate()
  8. {
  9. MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
  10. StackInit(&obj->pushST);
  11. StackInit(&obj->popST);
  12. return obj;
  13. }
  14. void myQueuePush(MyQueue* obj, int x)
  15. {
  16. StackPush(&obj->pushST, x);
  17. }
  18. void PushSTToPopST(MyQueue* obj)
  19. {
  20. if (StackEmpty(&obj->popST))
  21. {
  22. while (!StackEmpty(&obj->pushST))
  23. {
  24. StackPush(&obj->popST, StackTop(&obj->pushST));
  25. StackPop(&obj->pushST);
  26. }
  27. }
  28. }
  29. //删除队头元素并返回
  30. int myQueuePop(MyQueue* obj)
  31. {
  32. PushSTToPopST(obj);
  33. int front = StackTop(&obj->popST);
  34. StackPop(&obj->popST);
  35. return front;
  36. }
  37. //返回队头元素
  38. int myQueuePeek(MyQueue* obj)
  39. {
  40. PushSTToPopST(obj);
  41. return StackTop(&obj->popST);
  42. }
  43. bool myQueueEmpty(MyQueue* obj)
  44. {
  45. return StackEmpty(&obj->popST)
  46. && StackEmpty(&obj->pushST);
  47. }
  48. void myQueueFree(MyQueue* obj)
  49. {
  50. StackDestory(&obj->pushST);
  51. StackDestory(&obj->popST);
  52. free(obj);
  53. }

4.设计循环队列

  1. //设计循环队列
  2. //数组实现:
  3. typedef struct
  4. {
  5. int* a;
  6. int front;
  7. int back;
  8. int N;
  9. }MyCircularQueue;
  10. MyCircularQueue* myCircularQueue(int k)
  11. {
  12. MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  13. obj->a = (int*)malloc(sizeof(int) * (k + 1));
  14. obj->front = obj->back = 0;
  15. obj->N = k + 1;//队列中的空间个数
  16. return obj;
  17. }
  18. bool myCircularQueueIsEmpty(MyCircularQueue* obj)
  19. {
  20. return obj->front == obj->back;
  21. }
  22. bool myCircularQueueIsFull(MyCircularQueue* obj)
  23. {
  24. return ((obj->back + 1) % (obj->N)) == (obj->front);
  25. }
  26. //向循环队列插入一个元素 如果成功就返回真
  27. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
  28. {
  29. if (myCircularQueueIsFull(obj))
  30. return false;
  31. obj->a[obj->back] = value;
  32. obj->back++;
  33. //控制如果到空间尾以后 back回到0的位置
  34. obj->back %= obj->N;
  35. return true;
  36. }
  37. //向循环队列中删除一个元素 如果成功就返回真
  38. bool myCircularQueueDeQueue(MyCircularQueue* obj)
  39. {
  40. if (myCircularQueueIsEmpty(obj))
  41. return false;
  42. obj->front++;
  43. //控制如果到空间尾以后 front回到0的位置
  44. obj->front %= obj->N;
  45. return true;
  46. }
  47. //取队头数据
  48. int myCircularQueueFront(MyCircularQueue* obj)
  49. {
  50. if (myCircularQueueIsEmpty(obj))
  51. return -1;
  52. else
  53. return obj->a[obj->front];
  54. }
  55. //取队尾数据
  56. int myCircularQueueRear(MyCircularQueue* obj)
  57. {
  58. /*if (myCircularQueueIsEmpty(obj))
  59. return -1;
  60. else if (obj->back == 0)
  61. return obj->a[obj->N - 1];
  62. else
  63. return obj->a[obj->back - 1];*/
  64. if (myCircularQueueIsEmpty(obj))
  65. return -1;
  66. else
  67. return obj->a[(obj->back - 1 + obj->N) % obj->N];
  68. }
  69. void myCircularQueueFree(MyCircularQueue* obj)
  70. {
  71. free(obj->a);
  72. free(obj);
  73. }

概念选择题:

  1. 1.一个栈的初始状态为空。现将元素12345、A、B、C、D、E依次入栈,然后再依次出栈,则元素出
  2. 栈的顺序是( )。
  3. A 12345ABCDE
  4. B EDCBA54321
  5. C ABCDE12345
  6. D 54321EDCBA
  7. 2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
  8. A 1,4,3,2
  9. B 2,3,4,1
  10. C 3,1,4,2
  11. D 3,4,2,1
  12. 3.循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作
  13. 后, front=rear=99 ,则循环队列中的元素个数为( )
  14. A 1
  15. B 2
  16. C 99
  17. D 0或者100
  18. 4.以下( )不是队列的基本运算?
  19. A 从队尾插入一个新元素
  20. B 从队列中删除第i个元素
  21. C 判断一个队列是否为空
  22. D 读取队头元素的值
  23. 5.现有一循环队列,其队头指针为front,队尾指针为back;循环队列长度为N。其队内有效长度为?(假设多给一个空间,实际空间大小为N)
  24. A (back - front + N) % N + 1
  25. B (back - front + N) % N
  26. C (back - front) % (N + 1)
  27. D (back - front + N) % (N - 1)
  28. 注:(4 - 0 + 5) % 5 front在前 back在后
  29. 注:(0 - 4 + 5) % 5 back在前 front在后
  30. 答案:
  31. 1.B
  32. 2.C
  33. 3.D
  34. 4.B
  35. 5.B

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

闽ICP备14008679号