当前位置:   article > 正文

队列(C语言实现)_c语言队列

c语言队列

目录

一、队列的基本概念

1.队列的定义及其结构

2.队列的基本操作

二、队列的顺序存储结构

1.顺序存储

2.循环队列

3.循环队列实现

3.1循环队列定义

3.2 循环队列基本操作

3.3 功能实现(浪费一个空间的实现方式)

3.4 其他两种实现方式

三、队列的链式存储结构

1.链式存储队列定义

2.链式存储队列实现

四、双端队列(知识漏洞)

1.双端队列定义

2.输出受限的双端队列

3.输入受限的双端队列

4.特殊的双端队列

五、队列的应用

1.队列在层序遍历中的使用

2.队列实现栈


一、队列的基本概念

1.队列的定义及其结构

1.1 定义:队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出  FIFO(First In First Out)

入队列:进行插入操作的一端称为 队尾
出队列:进行删除操作的一端称为 队头
1.2结构:

2.队列的基本操作

  1. // 初始化队列
  2. void QueueInit(Queue* q);
  3. // 队尾入队列
  4. void QueuePush(Queue* q, QueDataType data);
  5. // 队头出队列
  6. void QueuePop(Queue* q);
  7. // 获取队列头部元素
  8. QueDataType QueueFront(Queue* q);
  9. // 获取队列队尾元素
  10. QueDataType QueueBack(Queue* q);
  11. // 获取队列中有效元素个数
  12. int QueueSize(Queue* q);
  13. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
  14. bool QueueEmpty(Queue* q);
  15. // 销毁队列
  16. void QueueDestroy(Queue* q);

二、队列的顺序存储结构

1.顺序存储

队列的顺序存储是指分配一块连续的存储单元存放队列中的元素,并附设两个指针:队头指针front指向队头元素,队尾指针rear指向队尾元素的下一个位置(front与rear定义不固定)。

初始时:rear=front=0

进队操作:队不满时,先送值到队尾元素,再将队尾指针+1;

出队操作:队不空时,先取队头元素值,再将队头指针+1;

注:rear==MaxSize不能作为判断队满的条件,如图(d),队列中仅有一个元素,但仍满足rear==MaxSize,这时入队出现“上溢出”,但这种溢出并不是真正的溢出,在data数组中依然存在可以存放元素的空位置,所以这是一种“假溢出”。

2.循环队列

把存储队列元素的顺序表从逻辑上视为一个环,成为循环队列。

当队首指针front=MaxSize-1后,再前进一个位置就自动到0,利用除法取余运算实现。

初始时:front=rear=0;

队首指针进1:front=(front+1)%MaxSize

队尾指针进1:rear=(rear+1)%MaxSize

队列长度:(rear+MaxSize-front)%MaxSize

队尾元素下标(出错点):(rear + MaxSize - 1)% MaxSize

出队入队时:指针都按顺时针方向进1

3.循环队列实现

MaxSize指的是定义的数组长度,并非队列的最大容量

比如:创建的队列容量为3,那么需要创建数组长度为4(因为要浪费一个空间),

此时的MaxSize为4

3.1循环队列定义

  1. typedef int DataType;
  2. typedef struct {
  3. DataType* arr;
  4. int front;
  5. int rear;
  6. int MaxSize;
  7. } MyCircularQueue;

3.2 循环队列基本操作

  1. //判断队满
  2. bool myCircularQueueIsFull(MyCircularQueue* obj);
  3. //判断队空
  4. bool myCircularQueueIsEmpty(MyCircularQueue* obj);
  5. //创建循环队列
  6. MyCircularQueue* myCircularQueueCreate(int k);
  7. //入队
  8. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value);
  9. //出队
  10. bool myCircularQueueDeQueue(MyCircularQueue* obj);
  11. //获取队首元素
  12. int myCircularQueueFront(MyCircularQueue* obj);
  13. //获取队尾元素
  14. int myCircularQueueRear(MyCircularQueue* obj);
  15. //队列销毁
  16. void myCircularQueueFree(MyCircularQueue* obj);

3.3 功能实现(浪费一个空间的实现方式)

  1. //判断队满
  2. bool myCircularQueueIsFull(MyCircularQueue* obj)
  3. {
  4. return (obj->rear + 1) % obj->MaxSize == obj->front;
  5. }
  6. //判断队空
  7. bool myCircularQueueIsEmpty(MyCircularQueue* obj)
  8. {
  9. return obj->rear == obj->front;
  10. }
  11. //创建循环队列
  12. MyCircularQueue* myCircularQueueCreate(int k)
  13. {
  14. MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  15. if (obj == NULL)
  16. {
  17. perror("malloc fail");
  18. return NULL;
  19. }
  20. obj->arr = (DataType*)malloc( sizeof(DataType) * (k + 1));
  21. if (obj->arr == NULL)
  22. {
  23. perror("malloc fail");
  24. return NULL;
  25. }
  26. obj->front = 0;
  27. obj->rear = 0;
  28. obj->MaxSize = k+1;
  29. return obj;
  30. }
  31. //入队
  32. bool myCircularQueueEnQueue(MyCircularQueue* obj, DataType value)
  33. {
  34. if (myCircularQueueIsFull(obj))
  35. {
  36. return false;
  37. }
  38. obj->arr[obj->rear] = value;
  39. obj->rear = (obj->rear + 1) % obj->MaxSize;
  40. return true;
  41. }
  42. //出队
  43. bool myCircularQueueDeQueue(MyCircularQueue* obj)
  44. {
  45. if (myCircularQueueIsEmpty(obj))
  46. {
  47. return false;
  48. }
  49. obj->front = (obj->front + 1) % obj->MaxSize;
  50. return true;
  51. }
  52. //获取队首元素
  53. DataType myCircularQueueFront(MyCircularQueue* obj)
  54. {
  55. assert(!myCircularQueueIsEmpty(obj));
  56. return obj->arr[obj->front];
  57. }
  58. //获取队尾元素
  59. DataType myCircularQueueRear(MyCircularQueue* obj)
  60. {
  61. assert(!myCircularQueueIsEmpty(obj));
  62. return obj->arr[(obj->rear + obj->MaxSize - 1)% obj->MaxSize] ;
  63. }
  64. //队列销毁
  65. void myCircularQueueFree(MyCircularQueue* obj)
  66. {
  67. free(obj->arr);
  68. obj->arr = NULL;
  69. obj->front = 0;
  70. obj->rear = 0;
  71. obj->MaxSize = 0;
  72. free(obj);
  73. }

3.4 其他两种实现方式

       核心在于区分队满与队空(两种情况都有rear==front)

(1)类型中增设表示元素个数的数据成员。

这样队空的条件为Q.size==0;

队满的条件为Q.size==MaxSize;

(2)类型中增设tag数据成员,以区分是队满还是队空。

tag等于0时,若因删除导致rear==front,则为队空

tag等于1时,若因插入导致rear==front,则为队满

三、队列的链式存储结构

1.链式存储队列定义

  1. typedef int QueDataType;
  2. typedef struct QueNode
  3. {
  4. struct QueNode* next;
  5. QueDataType data;
  6. }QueNode;
  7. typedef struct Queue
  8. {
  9. QueNode* front;
  10. QueNode* rear;
  11. int size;
  12. }Queue

2.链式存储队列实现

  1. /*
  2. 以无头单链表实现
  3. 头删出队列
  4. 尾插入队列
  5. */
  6. // 初始化队列
  7. void QueueInit(Queue* q)
  8. {
  9. q->front = NULL;
  10. q->rear = NULL;
  11. q->size = 0;
  12. }
  13. // 队尾入队列
  14. void QueuePush(Queue* q, QueDataType data)
  15. {
  16. assert(q);
  17. //实际上就是单链表尾插
  18. QueNode* newNode = (QueNode*)malloc(sizeof(QueNode));
  19. if (newNode == NULL)
  20. {
  21. perror("malloc fail");
  22. return;
  23. }
  24. newNode->data = data;
  25. if (QueueEmpty(q))
  26. {
  27. q->front = newNode;
  28. q->rear = newNode;
  29. }
  30. else
  31. {
  32. q->rear->next = newNode;
  33. q->rear = q->rear->next;
  34. }
  35. q->size++;
  36. }
  37. // 队头出队列
  38. void QueuePop(Queue* q)
  39. {
  40. assert(q);
  41. assert(!QueueEmpty(q));
  42. //实际上就是单链表头删
  43. if (q->size == 1 && q->front == q->rear)
  44. {
  45. QueNode* tmp = q->front;
  46. q->front == NULL;
  47. q->rear == NULL;
  48. free(tmp);
  49. }
  50. else
  51. {
  52. QueNode* tmp = q->front;
  53. q->front = q->front->next;
  54. free(tmp);
  55. }
  56. q->size--;
  57. }
  58. // 获取队列头部元素
  59. QueDataType QueueFront(Queue* q)
  60. {
  61. assert(q);
  62. assert(!QueueEmpty(q));
  63. return q->front->data;
  64. }
  65. // 获取队列队尾元素
  66. QueDataType QueueBack(Queue* q)
  67. {
  68. assert(q);
  69. assert(!QueueEmpty(q));
  70. return q->rear->data;
  71. }
  72. // 获取队列中有效元素个数
  73. int QueueSize(Queue* q)
  74. {
  75. assert(q);
  76. return q->size;
  77. }
  78. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
  79. bool QueueEmpty(Queue* q)
  80. {
  81. if ( q->size == 0)
  82. {
  83. return true;
  84. }
  85. else
  86. {
  87. return false;
  88. }
  89. }
  90. // 销毁队列
  91. void QueueDestroy(Queue* q)
  92. {
  93. while (q->size != 0)
  94. {
  95. QueNode* tmp = q->front;
  96. q->front = q->front->next;
  97. free(tmp);
  98. q->size--;
  99. }
  100. }

四、双端队列(知识漏洞)

1.双端队列定义

双端队列是指允许两端都可以进行入队和出队操作的队列。

其元素的逻辑结构仍是线性结构。将队列的两端称为前端和后端,两端都可以入队和出队。

2.输出受限的双端队列

允许在一段进行插入和删除,但另一端只允许插入的双端队列。

3.输入受限的双端队列

允许在一段进行插入和删除,但另一端只允许删除的双端队列。

4.特殊的双端队列

限定双端队列从某个端点插入的元素只能从该端点删除。

则该双端队列就蜕变为两个栈底相邻接的栈

五、队列的应用

1.队列在层序遍历中的使用

利用队列先进先出的性质

过程描述:

(1)根节点入队。

(2)若队空(所有结点都已处理完毕),则结束遍历;否则重复(3)的操作。

(3)队列中第一个结点出队,并访问之。若其有左孩子,则左孩子入队;若其有右孩子,则右孩子入队,返回(2)。

代码实现:

  1. // 层序遍历
  2. void BinaryTreeLevelOrder(tNode* root)
  3. {
  4. if (root == NULL)
  5. {
  6. return;
  7. }
  8. Queue* que = (Queue*)malloc(sizeof(Queue));
  9. if (que == NULL)
  10. {
  11. perror("malloc fail");
  12. return;
  13. }
  14. QueueInit(que);
  15. QueuePush(que,root);
  16. while (!QueueEmpty(que))
  17. {
  18. tNode* node = QueueFront(que);
  19. printf("%d ", node->val);
  20. QueuePop(que);
  21. if (node->left != NULL)
  22. {
  23. QueuePush(que, node->left);
  24. }
  25. if (node->right != NULL)
  26. {
  27. QueuePush(que, node->right);
  28. }
  29. }
  30. QueueDestroy(que);
  31. }

2.队列实现栈

思路:两个队列实现栈

push:若两个队列都为空,则是任意一个队列入队,否则,往非空的队列中入队

pop:将非空队列的数据依次出队,入队到另一个空队列直到剩下最后一个数据,将这个数据出队即完成出栈操作

top:非空队列的队尾是栈顶元素

关键在于:巧妙区分空队列和非空队列

  1. typedef struct {
  2. Queue que1;
  3. Queue que2;
  4. } MyStack;
  5. MyStack* myStackCreate() {
  6. MyStack* st=(MyStack*)malloc(sizeof(MyStack));
  7. QueueInit(&(st->que1));
  8. QueueInit(&(st->que2));
  9. return st;
  10. }
  11. void myStackPush(MyStack* obj, int x) {
  12. Queue* EmpQ =&(obj->que1);
  13. Queue* unEmpQ=&(obj->que2);
  14. if(!QueueEmpty(EmpQ))
  15. {
  16. unEmpQ=&(obj->que1);
  17. EmpQ=&(obj->que2);
  18. }
  19. QueuePush(unEmpQ,x);
  20. }
  21. int myStackPop(MyStack* obj) {
  22. Queue* EmpQ =&(obj->que1);
  23. Queue* unEmpQ=&(obj->que2);
  24. if(!QueueEmpty(EmpQ))
  25. {
  26. unEmpQ=&(obj->que1);
  27. EmpQ=&(obj->que2);
  28. }
  29. while(QueueSize(unEmpQ)>1)
  30. {
  31. int x=QueueFront(unEmpQ);
  32. QueuePop(unEmpQ);
  33. QueuePush(EmpQ,x);
  34. }
  35. int result=QueueFront(unEmpQ);
  36. QueuePop(unEmpQ);
  37. return result;
  38. }
  39. int myStackTop(MyStack* obj) {
  40. Queue* EmpQ =&(obj->que1);
  41. Queue* unEmpQ=&(obj->que2);
  42. if(!QueueEmpty(EmpQ))
  43. {
  44. unEmpQ=&(obj->que1);
  45. EmpQ=&(obj->que2);
  46. }
  47. int result=QueueBack(unEmpQ);
  48. return result;
  49. }
  50. bool myStackEmpty(MyStack* obj) {
  51. Queue* EmpQ =&(obj->que1);
  52. Queue* unEmpQ=&(obj->que2);
  53. if(QueueEmpty(EmpQ)&&QueueEmpty(unEmpQ))
  54. {
  55. return true;
  56. }
  57. return false;
  58. }
  59. void myStackFree(MyStack* obj) {
  60. Queue* EmpQ =&(obj->que1);
  61. Queue* unEmpQ=&(obj->que2);
  62. QueueDestroy(EmpQ);
  63. QueueDestroy(unEmpQ);
  64. free(obj);
  65. }

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

闽ICP备14008679号