当前位置:   article > 正文

队列 结构详解(顺序/链式队列、循环队列、优先队列、高并发WEB服务队列)(C/C++)_链式排队器的优先级

链式排队器的优先级

目录

一、队列的原理精讲

二、队列算法实现 

2.1顺序存储

2.2链式存储

三、队列实际开发应用案例

3.1线程池中的任务队列

3.2循坏队列

 3.3优先队列

3.4动态队列

3.5高并发WEB服务器队列的应用

顺序队列完整代码

链式队列完整代码

线程池中的任务队列完整代码

循环队列完整代码

优先队列完整代码


一、队列的原理精讲

队列是一种受限的线性表, (Queue), 它是一种运算受限的线性表,先进先出(FIFO First In First Out) 

        队列是一种受限的线性结构
        它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
生活中队列场景随处可见: 比如在电影院, 商场, 或者厕所排队.......


二、队列算法实现 

2.1顺序存储

采用数组来保存队列的元素,设立一个队首指针 front ,一个队尾指针 rear,分别指向队首和队尾元素。则rear-front 即为存储的元素个数! 

  1. #define MaxSize 5 //队列的最大容量
  2. typedef int DataType; //队列中元素类型
  3. typedef struct Queue{
  4. DataType queue[MaxSize];
  5. int front; //队头指针
  6. int rear; //队尾指针
  7. }SeqQueue;

 队列初始化

  1. //队列初始化,将队列初始化为空队列
  2. void InitQueue(SeqQueue* SQ){
  3. if (!SQ) return;
  4. SQ->front = SQ->rear = 0; //把对头和队尾指针同时置 0
  5. }

 队列为空

  1. //判断队列为空
  2. int IsEmpty(SeqQueue* SQ){
  3. if (!SQ) return 0;
  4. if (SQ->front == SQ->rear){
  5. return 1;
  6. }
  7. return 0;
  8. }

 队列为满

  1. //判断队列是否为满
  2. int IsFull(SeqQueue* SQ){
  3. if (!SQ) return 0;
  4. if (SQ->rear == MaxSize){
  5. return 1;
  6. }
  7. return 0;
  8. }

 入队:将新元素插入 rear 所指的位置,然后 rear 加 1。

  1. //入队,将元素 data 插入到队列 SQ 中
  2. int EnterQueue(SeqQueue* SQ, DataType data) {
  3. if (!SQ) return 0;
  4. if (IsFull(SQ)) {
  5. cout << "无法插入元素 " << data << ", 队列已满!" << endl;
  6. return 0;
  7. }
  8. SQ->queue[SQ->rear] = data; //在队尾插入元素 data
  9. SQ->rear++; //队尾指针后移一位
  10. return 1;
  11. }

 打印队列中的元素

  1. //打印队列中的各元素
  2. void PrintQueue(SeqQueue* SQ){
  3. if (!SQ) return;
  4. int i = SQ->front;
  5. while (i < SQ->rear){
  6. //setw() 用于控制输出之间的间隔,setw(4)可以使前后输出间隔4字符,头文件#include <iomanip>
  7. cout << setw(4) << SQ->queue[i];
  8. i++;
  9. }
  10. cout << endl;
  11. }

 //setw() 用于控制输出之间的间隔,setw(4)可以使前后输出间隔4字符,头文件#include <iomanip>。

出队 方式 1 —— 删除 front 所指的元素, 后面所有元素前移 1 并返回被删除元素。

  1. //出队,将队列中队头的元素 data 出队,后面的元素向前移动
  2. int DeleteQueue(SeqQueue* SQ, DataType* data) {
  3. if (!SQ || IsEmpty(SQ)) {
  4. cout << "队列为空!" << endl;
  5. return 0;
  6. }
  7. if (!data) return 0;
  8. *data = SQ->queue[SQ->front];
  9. for (int i = SQ->front + 1; i < SQ->rear; i++) {//移动后面的元素
  10. SQ->queue[i - 1] = SQ->queue[i];
  11. }
  12. SQ->rear--;//队尾指针前移一位
  13. return 1;
  14. }

 出队 方式 2 —— 删除 front 所指的元素,然后加 1 并返回被删元素。

  1. //出队,将队列中队头的元素 data 出队,出队后队头指针 front 后移一位
  2. int DeleteQueue2(SeqQueue* SQ, DataType* data){
  3. if (!SQ || IsEmpty(SQ)){
  4. cout << "队列为空!" << endl;
  5. return 0;
  6. }
  7. if (SQ->front >= MaxSize) {
  8. cout << "队列已到尽头!" << endl;
  9. return 0;
  10. }
  11. *data = SQ->queue[SQ->front]; //出队元素值
  12. SQ->front = (SQ->front) + 1; //队首指针后移一位
  13. return 1;
  14. }

 取队首元素:返回 front 指向的元素值

  1. //获取队首元素
  2. int GetHead(SeqQueue* SQ, DataType* data){
  3. if (!SQ || IsEmpty(SQ)){
  4. cout << "队列为空!" << endl;
  5. }
  6. return *data = SQ->queue[SQ->front];
  7. }

 清空队列

  1. //清空队列
  2. void ClearQueue(SeqQueue* SQ){
  3. SQ->front = SQ->rear = 0;
  4. }

 顺序队列文章结尾有完整代码~


2.2链式存储

队列的链式存储结构,其实就是线性表的单链表,只不过它只是尾进头出而已,我们把它简称为链队列。为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端节点 。

 

 

  1. typedef int DataType; //队列中元素类型
  2. typedef struct _QNode { //结点结构
  3. DataType data;
  4. struct _QNode* next;
  5. }QNode;
  6. typedef QNode* QueuePtr;
  7. typedef struct Queue{
  8. int length; //队列的长度
  9. QueuePtr front; //队头指针
  10. QueuePtr rear; //队尾指针
  11. }LinkQueue;

链式队列操作图示
空队列时,front 和 rear 都指向空。 

 删除节点

 链式队列文章结尾有完整代码~


三、队列实际开发应用案例

3.1线程池中的任务队列

 线程池 —— 由一个任务队列和一组处理队列的线程组成。一旦工作进程需要处理某个可能“阻塞”的操作,不用自己操作,将其作为一个任务放到线程池的队列,接着会被某个空闲线程提取处理。

  1. typedef struct _QNode { //结点结构
  2. int id;
  3. void (*handler)();
  4. struct _QNode* next;
  5. }QNode;
  6. typedef QNode* QueuePtr;
  7. typedef struct Queue{
  8. int length; //队列的长度
  9. QueuePtr front; //队头指针
  10. QueuePtr rear; //队尾指针
  11. }LinkQueue;

线程池中的任务队列 文章结尾有完整代码~


3.2循坏队列

 在队列的顺序存储中,采用出队方式 2, 删除 front 所指的元素,然后加 1 并返回被删元素。这样可以避免元素移动,但是也带来了一个新的问题“假溢出”。

 能否利用前面的空间继续存储入队呢?采用 循环队列

 

循环队列入队, 队尾循环后移: SQ->rear =(SQ->rear+1)%Maxsize;
循环队列出队, 队首循环后移: SQ->front =(SQ->front+1)%Maxsize;
队空:SQ.front=SQ.rear; // SQ.rear 和 SQ.front 指向同一个位置
队满: (SQ.rear+1) %Maxsize=SQ.front; // SQ.rear 向后移一位正好是 SQ.front

 计算元素个数:
可以分两种情况判断:
        如果 SQ.rear>= SQ.front:元素个数为 SQ.rear-SQ.front;
        如果 SQ.rear<SQ.front:元素个数为 SQ.rear-SQ.front+ Maxsize;
采用取模的方法把两种情况统一为:(SQ.rear-SQ.front+Maxsize)% Maxsize

循环队列文章结尾有完整代码


 3.3优先队列

 英雄联盟游戏里面防御塔都有一个自动攻击功能,小兵排着队进入防御塔的攻击范围,防御塔先攻击靠得最近的小兵,这时候大炮车的优先级更高(因为系统判定大炮车对于防御塔的威胁大),所以防御塔会优先攻击大炮车。而当大炮车阵亡,剩下的全部都是普通小兵,这时候离得近的优先级越高,防御塔优先攻击距离更近的小兵。

优先队列 : 它的入队顺序没有变化,但是出队的顺序是根据优先级的高低来决定的。优先级高的
优先出队。 

  1. typedef int DataType; //队列中元素类型
  2. typedef struct _QNode { //结点结构
  3. int priority; //每个节点的优先级,9 最高优先级,0 最低优先级,优先级相同,取第一个节点
  4. DataType data;
  5. struct _QNode* next;
  6. }QNode;
  7. typedef QNode* QueuePtr;
  8. typedef struct Queue
  9. {
  10. int length; //队列的长度
  11. QueuePtr front; //队头指针
  12. QueuePtr rear; //队尾指针
  13. }LinkQueue;

 空的任务队列 & 插入元素

 删除一个节点

 优先队列出队

 优先队列文章结尾有完整代码~


3.4动态队列

使用链表动态存储的队列即为动态顺序队列~前面已经实现,故不再重复!


3.5高并发WEB服务器队列的应用

在高并发 HTTP 反向代理服务器 Nginx 中,存在着一个跟性能息息相关的模块 - 文件缓存。 

         经常访问到的文件会被 nginx 从磁盘缓存到内存,这样可以极大的提高 Nginx 的并发能力,不过因为内存的限制,当缓存的文件数达到一定程度的时候就会采取淘汰机制,优先淘汰进入时间比较久或是最近访问很少(LRU)的队列文件。

 具体实现方案:

1. 使用双向循环队列保存缓存的文件节点,这样可以实现多种淘汰策略:
        比如:如果采用淘汰进入时间比较久的策略,就可以使用队列的特性,先进先出
                如果要采用按照 LRU,就遍历链表,找到节点删除。 

源码实现

 nginx_queue.h

  1. #ifndef _NGX_QUEUE_H_INCLUDED_
  2. #define _NGX_QUEUE_H_INCLUDED_
  3. typedef struct ngx_queue_s ngx_queue_t;
  4. struct ngx_queue_s {
  5. ngx_queue_t* prev;
  6. ngx_queue_t* next;
  7. };
  8. #define ngx_queue_init(q) \
  9. (q)->prev = q; \
  10. (q)->next = q
  11. #define ngx_queue_empty(h) \
  12. (h == (h)->prev)
  13. #define ngx_queue_insert_head(h, x) \
  14. (x)->next = (h)->next; \
  15. (x)->next->prev = x; \
  16. (x)->prev = h; \
  17. (h)->next = x
  18. #define ngx_queue_insert_after ngx_queue_insert_head
  19. #define ngx_queue_insert_tail(h, x) \
  20. (x)->prev = (h)->prev; \
  21. (x)->prev->next = x; \
  22. (x)->next = h; \
  23. (h)->prev = x
  24. #define ngx_queue_head(h) \
  25. (h)->next
  26. #define ngx_queue_last(h) \
  27. (h)->prev
  28. #define ngx_queue_sentinel(h) \
  29. (h)
  30. #define ngx_queue_next(q) \
  31. (q)->next
  32. #define ngx_queue_prev(q) \
  33. (q)->prev
  34. #define ngx_queue_remove(x) \
  35. (x)->next->prev = (x)->prev; \
  36. (x)->prev->next = (x)->next
  37. #define ngx_queue_data(q, type, link) \
  38. (type *) ((char *) q - offsetof(type, link))
  39. #endif

 Nginx_双向循环队列.cpp

  1. #include <Windows.h>
  2. #include <stdlib.h>
  3. #include <iostream>
  4. #include "nginx_queue.h"
  5. #include <time.h>
  6. using namespace std;
  7. typedef struct ngx_cached_open_file_s {
  8. //其它属性省略...
  9. int fd;
  10. ngx_queue_t queue;
  11. }ngx_cached_file_t;
  12. typedef struct {
  13. //其它属性省略...
  14. ngx_queue_t expire_queue;
  15. //其它属性省略...
  16. } ngx_open_file_cache_t;
  17. int main(void) {
  18. ngx_open_file_cache_t* cache = new ngx_open_file_cache_t;
  19. ngx_queue_t* q;
  20. ngx_queue_init(&cache->expire_queue);
  21. //1. 模拟文件模块,增加打开的文件到缓存中
  22. for (int i = 0; i < 10; i++) {
  23. ngx_cached_file_t* e = new ngx_cached_file_t;
  24. e->fd = i;
  25. ngx_queue_insert_head(&cache->expire_queue, &e->queue);
  26. }
  27. //遍历队列
  28. for (q = cache->expire_queue.next;
  29. q != ngx_queue_sentinel(&cache->expire_queue); q = q->next) {
  30. printf("队列中的元素:%d\n", (ngx_queue_data(q,
  31. ngx_cached_file_t, queue))->fd);
  32. }
  33. //模拟缓存的文件到期,执行出列操作
  34. while (!ngx_queue_empty(&cache->expire_queue)) {
  35. q = ngx_queue_last(&cache->expire_queue);
  36. ngx_cached_file_t* cached_file = ngx_queue_data(q,
  37. ngx_cached_file_t, queue);
  38. printf("出队列中的元素:%d\n", cached_file->fd);
  39. ngx_queue_remove(q);
  40. delete(cached_file);
  41. }
  42. system("pause");
  43. return 0;
  44. }

顺序队列完整代码

  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <Windows.h>
  4. #include <iostream>
  5. #include <iomanip>
  6. using namespace std;
  7. #define MaxSize 5 //队列的最大容量
  8. typedef int DataType; //队列中元素类型
  9. typedef struct Queue{
  10. DataType queue[MaxSize];
  11. int front; //队头指针
  12. int rear; //队尾指针
  13. }SeqQueue;
  14. //队列初始化,将队列初始化为空队列
  15. void InitQueue(SeqQueue * SQ){
  16. if (!SQ) return;
  17. SQ->front = SQ->rear = 0; //把对头和队尾指针同时置 0
  18. }
  19. //判断队列为空
  20. int IsEmpty(SeqQueue* SQ){
  21. if (!SQ) return 0;
  22. if (SQ->front == SQ->rear){
  23. return 1;
  24. }
  25. return 0;
  26. }
  27. //判断队列是否为满
  28. int IsFull(SeqQueue* SQ){
  29. if (!SQ) return 0;
  30. if (SQ->rear == MaxSize){
  31. return 1;
  32. }
  33. return 0;
  34. }
  35. //入队,将元素 data 插入到队列 SQ 中
  36. int EnterQueue(SeqQueue* SQ, DataType data) {
  37. if (!SQ) return 0;
  38. if (IsFull(SQ)) {
  39. cout << "无法插入元素 " << data << ", 队列已满!" << endl;
  40. return 0;
  41. }
  42. SQ->queue[SQ->rear] = data; //在队尾插入元素 data
  43. SQ->rear++; //队尾指针后移一位
  44. return 1;
  45. }
  46. //出队,将队列中队头的元素 data 出队,后面的元素向前移动
  47. int DeleteQueue(SeqQueue* SQ, DataType* data) {
  48. if (!SQ || IsEmpty(SQ)) {
  49. cout << "队列为空!" << endl;
  50. return 0;
  51. }
  52. if (!data) return 0;
  53. *data = SQ->queue[SQ->front];
  54. for (int i = SQ->front + 1; i < SQ->rear; i++) {//移动后面的元素
  55. SQ->queue[i - 1] = SQ->queue[i];
  56. }
  57. SQ->rear--;//队尾指针前移一位
  58. return 1;
  59. }
  60. //出队,将队列中队头的元素 data 出队,出队后队头指针 front 后移一位
  61. int DeleteQueue2(SeqQueue* SQ, DataType* data){
  62. if (!SQ || IsEmpty(SQ)){
  63. cout << "队列为空!" << endl;
  64. return 0;
  65. }
  66. if (SQ->front >= MaxSize) {
  67. cout << "队列已到尽头!" << endl;
  68. return 0;
  69. }
  70. *data = SQ->queue[SQ->front]; //出队元素值
  71. SQ->front = (SQ->front) + 1; //队首指针后移一位
  72. return 1;
  73. }
  74. //打印队列中的各元素
  75. void PrintQueue(SeqQueue* SQ){
  76. if (!SQ) return;
  77. int i = SQ->front;
  78. while (i < SQ->rear){
  79. cout << setw(4) << SQ->queue[i];
  80. i++;
  81. }
  82. cout << endl;
  83. }
  84. //获取队首元素,不出队
  85. int GetHead(SeqQueue* SQ, DataType* data){
  86. if (!SQ || IsEmpty(SQ)){
  87. cout << "队列为空!" << endl;
  88. }
  89. return *data = SQ->queue[SQ->front];
  90. }
  91. //清空队列
  92. void ClearQueue(SeqQueue* SQ){
  93. if (!SQ) return;
  94. SQ->front = SQ->rear = 0;
  95. }
  96. //获取队列中元素的个数
  97. int getLength(SeqQueue* SQ) {
  98. if (!SQ) return 0;
  99. return SQ->rear - SQ->front;
  100. }
  101. int main(){
  102. SeqQueue* SQ = new SeqQueue;
  103. DataType data = -1;
  104. //初始化队列
  105. InitQueue(SQ);
  106. //入队
  107. for (int i = 0; i < 7; i++) {
  108. EnterQueue(SQ, i);
  109. }
  110. //打印队列中的元素
  111. printf("队列中的元素(总共%d 个):", getLength(SQ));
  112. PrintQueue(SQ);
  113. cout << endl;
  114. //出队
  115. //for(int i=0; i<10; i++){
  116. if (DeleteQueue2(SQ, &data)) {
  117. cout << "出队的元素是:" << data << endl;
  118. }
  119. else {
  120. cout << "出队失败!" << endl;
  121. }
  122. //}
  123. //打印队列中的元素
  124. printf("出队一个元素后,队列中剩下的元素:");
  125. PrintQueue(SQ);
  126. cout << endl;
  127. system("pause");
  128. return 0;
  129. }

 链式队列完整代码

  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <Windows.h>
  4. #include <iostream>
  5. #include <iomanip>
  6. using namespace std;
  7. #define MaxSize 5 //队列的最大容量
  8. typedef int DataType; //队列中元素类型
  9. typedef struct _QNode { //结点结构
  10. DataType data;
  11. struct _QNode* next;
  12. }QNode;
  13. typedef QNode* QueuePtr;
  14. typedef struct Queue{
  15. int length; //队列的长度
  16. QueuePtr front; //队头指针
  17. QueuePtr rear; //队尾指针
  18. }LinkQueue;
  19. //队列初始化,将队列初始化为空队列
  20. void InitQueue(LinkQueue* LQ){
  21. if (!LQ) return;
  22. LQ->length = 0;
  23. LQ->front = LQ->rear = NULL; //把对头和队尾指针同时置 0
  24. }
  25. //判断队列为空
  26. int IsEmpty(LinkQueue* LQ){
  27. if (!LQ) return 0;
  28. if (LQ->front == NULL){
  29. return 1;
  30. }
  31. return 0;
  32. }
  33. //判断队列是否为满
  34. int IsFull(LinkQueue* LQ){
  35. if (!LQ) return 0;
  36. if (LQ->length == MaxSize){
  37. return 1;
  38. }
  39. return 0;
  40. }
  41. //入队,将元素 data 插入到队列 LQ 中
  42. int EnterQueue(LinkQueue* LQ, DataType data) {
  43. if (!LQ) return 0;
  44. if (IsFull(LQ)) {
  45. cout << "无法插入元素 " << data << ", 队列已满!" << endl;
  46. return 0;
  47. }
  48. QNode* qNode = new QNode;
  49. qNode->data = data;
  50. qNode->next = NULL;
  51. if (IsEmpty(LQ)) {//空队列
  52. LQ->front = LQ->rear = qNode;
  53. }
  54. else {
  55. LQ->rear->next = qNode;//在队尾插入节点 qNode
  56. LQ->rear = qNode; //队尾指向新插入的节点
  57. }
  58. LQ->length++;
  59. return 1;
  60. }
  61. //出队,将队列中队头的元素出队,其后的第一个元素成为新的队首
  62. int DeleteQueue(LinkQueue* LQ, DataType* data) {
  63. QNode* tmp = NULL;
  64. if (!LQ || IsEmpty(LQ)) {
  65. cout << "队列为空!" << endl;
  66. return 0;
  67. }
  68. if (!data) return 0;
  69. tmp = LQ->front;
  70. LQ->front = tmp->next;
  71. if (!LQ->front) LQ->rear = NULL;//如果对头出列后不存在其他元素,则rear 节点也要置空
  72. * data = tmp->data;
  73. LQ->length--;
  74. delete tmp;
  75. return 1;
  76. }
  77. //打印队列中的各元素
  78. void PrintQueue(LinkQueue* LQ){
  79. QueuePtr tmp;
  80. if (!LQ) return;
  81. if (LQ->front == NULL) {
  82. cout << "队列为空!";
  83. return;
  84. }
  85. tmp = LQ->front;
  86. while (tmp){
  87. cout << setw(4) << tmp->data;
  88. tmp = tmp->next;
  89. }
  90. cout << endl;
  91. }
  92. //获取队首元素,不出队
  93. int GetHead(LinkQueue* LQ, DataType* data)
  94. {
  95. if (!LQ || IsEmpty(LQ)){
  96. cout << "队列为空!" << endl;
  97. return 0;
  98. }
  99. if (!data) return 0;
  100. *data = LQ->front->data;
  101. return 1;
  102. }
  103. //清空队列
  104. void ClearQueue(LinkQueue* LQ){
  105. if (!LQ) return;
  106. while (LQ->front) {
  107. QueuePtr tmp = LQ->front->next;
  108. delete LQ->front;
  109. LQ->front = tmp;
  110. }
  111. LQ->front = LQ->rear = NULL;
  112. LQ->length = 0;
  113. }
  114. //获取队列中元素的个数
  115. int getLength(LinkQueue* LQ) {
  116. if (!LQ) return 0;
  117. return LQ->length;
  118. }
  119. int main(){
  120. LinkQueue* LQ = new LinkQueue;
  121. DataType data = -1;
  122. //初始化队列
  123. InitQueue(LQ);
  124. //入队
  125. for (int i = 0; i < 7; i++) {
  126. EnterQueue(LQ, i);
  127. }
  128. //打印队列中的元素
  129. printf("队列中的元素(总共%d 个):", getLength(LQ));
  130. PrintQueue(LQ);
  131. cout << endl;
  132. //出队
  133. //for(int i=0; i<10; i++){
  134. if (DeleteQueue(LQ, &data)) {
  135. cout << "出队的元素是:" << data << endl;
  136. }
  137. else {
  138. cout << "出队失败!" << endl;
  139. }
  140. //}
  141. //打印队列中的元素
  142. printf("出队一个元素后,队列中剩下的元素[%d]:", getLength(LQ));
  143. PrintQueue(LQ);
  144. cout << endl;
  145. ClearQueue(LQ);
  146. cout << "清空队列!\n";
  147. PrintQueue(LQ);
  148. //清理资源
  149. delete LQ;
  150. system("pause");
  151. return 0;
  152. }

线程池中的任务队列完整代码

  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <Windows.h>
  4. #include <iostream>
  5. #include <iomanip>
  6. using namespace std;
  7. #define MaxSize 1000 //队列的最大容量
  8. typedef struct _QNode { //任务结点结构
  9. int id;
  10. void (*handler)(void);
  11. struct _QNode* next;
  12. }QNode;
  13. typedef QNode* QueuePtr;
  14. typedef struct Queue{
  15. int length; //队列的长度
  16. QueuePtr front; //队头指针
  17. QueuePtr rear; //队尾指针
  18. }LinkQueue;
  19. //分配线程执行的任务节点
  20. QueuePtr thread_task_alloc(){
  21. QNode* task;
  22. task = (QNode*)calloc(1, sizeof(QNode));
  23. if (task == NULL) {
  24. return NULL;
  25. }
  26. return task;
  27. }
  28. //队列初始化,将队列初始化为空队列
  29. void InitQueue(LinkQueue* LQ){
  30. if (!LQ) return;
  31. LQ->length = 0;
  32. LQ->front = LQ->rear = NULL; //把对头和队尾指针同时置 0
  33. }
  34. //判断队列为空
  35. int IsEmpty(LinkQueue * LQ){
  36. if (!LQ) return 0;
  37. if (LQ->front == NULL){
  38. return 1;
  39. }
  40. return 0;
  41. }
  42. //判断队列是否为满
  43. int IsFull(LinkQueue* LQ){
  44. if (!LQ) return 0;
  45. if (LQ->length == MaxSize){
  46. return 1;
  47. }
  48. return 0;
  49. }
  50. //入队,将元素 data 插入到队列 LQ 中
  51. int EnterQueue(LinkQueue* LQ, QNode* node) {
  52. if (!LQ || !node) return 0;
  53. if (IsFull(LQ)) {
  54. cout << "无法插入任务 " << node->id << ", 队列已满!" << endl;
  55. return 0;
  56. }
  57. node->next = NULL;
  58. if (IsEmpty(LQ)) {//空队列
  59. LQ->front = LQ->rear = node;
  60. }
  61. else {
  62. LQ->rear->next = node;//在队尾插入节点 qNode
  63. LQ->rear = node; //队尾指向新插入的节点
  64. }
  65. LQ->length++;
  66. return 1;
  67. }
  68. //出队,将队列中队头的节点出队,返回头节点
  69. QNode * PopQueue(LinkQueue * LQ) {
  70. QNode* tmp = NULL;
  71. if (!LQ || IsEmpty(LQ)) {
  72. cout << "队列为空!" << endl;
  73. return 0;
  74. }
  75. tmp = LQ->front;
  76. LQ->front = tmp->next;
  77. if (!LQ->front) LQ->rear = NULL;//如果对头出列后不存在其他元素,则rear 节点也要置空
  78. LQ->length--;
  79. return tmp;
  80. }
  81. //打印队列中的各元素
  82. void PrintQueue(LinkQueue* LQ{
  83. QueuePtr tmp;
  84. if (!LQ) return;
  85. if (LQ->front == NULL) {
  86. cout << "队列为空!";
  87. return;
  88. }
  89. tmp = LQ->front;
  90. while (tmp){
  91. cout << setw(4) << tmp->id;
  92. tmp = tmp->next;
  93. }
  94. cout << endl;
  95. }
  96. //获取队列中元素的个数
  97. int getLength(LinkQueue* LQ) {
  98. if (!LQ) return 0;
  99. return LQ->length;
  100. }
  101. void task1() {
  102. printf("我是任务 1 ...\n");
  103. }
  104. void task2() {
  105. printf("我是任务 2 ...\n");
  106. }
  107. int main()
  108. {
  109. LinkQueue* LQ = new LinkQueue;
  110. QNode* task = NULL;
  111. //初始化队列
  112. InitQueue(LQ);
  113. //任务 1 入队
  114. task = thread_task_alloc();
  115. task->id = 1;
  116. task->handler = &task1;
  117. EnterQueue(LQ, task);
  118. //任务 2 入队
  119. task = thread_task_alloc();
  120. task->id = 2;
  121. task->handler = &task2;
  122. EnterQueue(LQ, task);
  123. //打印任务队列中的元素
  124. printf("队列中的元素(总共%d 个):", getLength(LQ));
  125. PrintQueue(LQ);
  126. cout << endl;
  127. //执行任务
  128. while ((task = PopQueue(LQ))) {
  129. task->handler();
  130. delete task;
  131. }
  132. //清理资源
  133. delete LQ;
  134. system("pause");
  135. return 0;
  136. }

循环队列完整代码

  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <Windows.h>
  4. #include <iostream>
  5. #include <iomanip>
  6. using namespace std;
  7. #define MaxSize 5 //循环队列的最大容量
  8. typedef int DataType; //循环队列中元素类型
  9. typedef struct Queue
  10. {
  11. DataType queue[MaxSize];
  12. int front; //循环队头指针
  13. int rear; //循环队尾指针
  14. }SeqQueue;
  15. //队列初始化,将循环队列初始化为空队列
  16. void InitQueue(SeqQueue* SQ)
  17. {
  18. if (!SQ) return;
  19. SQ->front = SQ->rear = 0; //把对头和队尾指针同时置 0
  20. }
  21. //判断队列为空
  22. int IsEmpty(SeqQueue* SQ){
  23. if (!SQ) return 0;
  24. if (SQ->front == SQ->rear){
  25. return 1;
  26. }
  27. return 0;
  28. }
  29. //判断循环队列是否为满
  30. int IsFull(SeqQueue* SQ){
  31. if (!SQ) return 0;
  32. if ((SQ->rear + 1) % MaxSize == SQ->front){
  33. return 1;
  34. }
  35. return 0;
  36. }
  37. //入队,将元素 data 插入到循环队列 SQ 中
  38. int EnterQueue(SeqQueue* SQ, DataType data) {
  39. if (!SQ) return 0;
  40. if (IsFull(SQ)) {
  41. cout << "无法插入元素 " << data << ", 队列已满!" << endl;
  42. return 0;
  43. }
  44. SQ->queue[SQ->rear] = data; //在队尾插入元素 data
  45. SQ->rear = (SQ->rear + 1) % MaxSize; //队尾指针循环后移一位
  46. return 1;
  47. }
  48. //出队,将队列中队头的元素 data 出队,出队后队头指针 front 后移一位
  49. int DeleteQueue(SeqQueue* SQ, DataType* data){
  50. if (!SQ || IsEmpty(SQ)){
  51. cout << "循环队列为空!" << endl;
  52. return 0;
  53. }
  54. *data = SQ->queue[SQ->front]; //出队元素值
  55. SQ->front = (SQ->front + 1) % MaxSize; //队首指针后移一位
  56. return 1;
  57. }
  58. //打印队列中的各元素
  59. void PrintQueue(SeqQueue* SQ){
  60. if (!SQ) return;
  61. int i = SQ->front;
  62. while (i != SQ->rear){
  63. cout << setw(4) << SQ->queue[i];
  64. i = (i + 1) % MaxSize;
  65. }
  66. cout << endl;
  67. }
  68. //获取队首元素,不出队
  69. int GetHead(SeqQueue* SQ, DataType* data){
  70. if (!SQ || IsEmpty(SQ)){
  71. cout << "队列为空!" << endl;
  72. }
  73. return *data = SQ->queue[SQ->front];
  74. }
  75. //清空队列
  76. void ClearQueue(SeqQueue* SQ){
  77. if (!SQ) return;
  78. SQ->front = SQ->rear = 0;
  79. }
  80. //获取队列中元素的个数
  81. int getLength(SeqQueue* SQ) {
  82. if (!SQ) return 0;
  83. return (SQ->rear - SQ->front + MaxSize) % MaxSize;
  84. }
  85. int main(){
  86. SeqQueue* SQ = new SeqQueue;
  87. DataType data = -1;
  88. //初始化队列
  89. InitQueue(SQ);
  90. //入队
  91. for (int i = 0; i < 7; i++) {
  92. EnterQueue(SQ, i);
  93. }
  94. //打印队列中的元素
  95. printf("队列中的元素(总共%d 个):", getLength(SQ));
  96. PrintQueue(SQ);
  97. cout << endl;
  98. //出队
  99. for (int i = 0; i < 5; i++) {
  100. if (DeleteQueue(SQ, &data)) {
  101. cout << "出队的元素是:" << data << endl;
  102. }
  103. else {
  104. cout << "出队失败!" << endl;
  105. }
  106. }
  107. //打印队列中的元素
  108. printf("出队五个元素后,队列中剩下的元素个数为 %d 个:",
  109. getLength(SQ));
  110. PrintQueue(SQ);
  111. cout << endl;
  112. //入队 4 个
  113. for (int i = 0; i < 4; i++) {
  114. EnterQueue(SQ, i + 10);
  115. }
  116. printf("\n 入队四个元素后,队列中剩下的元素个数为 %d 个:",
  117. getLength(SQ));
  118. PrintQueue(SQ);
  119. system("pause");
  120. return 0;
  121. }

 优先队列完整代码

  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <Windows.h>
  4. #include <iostream>
  5. #include <iomanip>
  6. using namespace std;
  7. #define MaxSize 5 //队列的最大容量
  8. typedef int DataType; //任务队列中元素类型
  9. typedef struct _QNode { //结点结构
  10. int priority; //每个节点的优先级,0 最低优先级,9 最高优先级,优先级相同,取第一个节点
  11. DataType data;
  12. struct _QNode* next;
  13. }QNode;
  14. typedef QNode* QueuePtr;
  15. typedef struct Queue{
  16. int length; //队列的长度
  17. QueuePtr front; //队头指针
  18. QueuePtr rear; //队尾指针
  19. }LinkQueue;
  20. //队列初始化,将队列初始化为空队列
  21. void InitQueue(LinkQueue* LQ){
  22. if (!LQ) return;
  23. LQ->length = 0;
  24. LQ->front = LQ->rear = NULL; //把对头和队尾指针同时置 0
  25. }
  26. //判断队列为空
  27. int IsEmpty(LinkQueue* LQ){
  28. if (!LQ) return 0;
  29. if (LQ->front == NULL){
  30. return 1;
  31. }
  32. return 0;
  33. }
  34. //判断队列是否为满
  35. int IsFull(LinkQueue* LQ){
  36. if (!LQ) return 0;
  37. if (LQ->length == MaxSize){
  38. return 1;
  39. }
  40. return 0;
  41. }
  42. //入队,将元素 data 插入到队列 LQ 中
  43. int EnterQueue(LinkQueue* LQ, DataType data, int priority) {
  44. if (!LQ) return 0;
  45. if (IsFull(LQ)) {
  46. cout << "无法插入元素 " << data << ", 队列已满!" << endl;
  47. return 0;
  48. }
  49. QNode* qNode = new QNode;
  50. qNode->data = data;
  51. qNode->priority = priority;
  52. qNode->next = NULL;
  53. if (IsEmpty(LQ)) {//空队列
  54. LQ->front = LQ->rear = qNode;
  55. }
  56. else {
  57. LQ->rear->next = qNode;//在队尾插入节点 qNode
  58. LQ->rear = qNode; //队尾指向新插入的节点
  59. }
  60. LQ->length++;
  61. return 1;
  62. }
  63. //出队,遍历队列,找到队列中优先级最高的元素 data 出队
  64. int DeleteQueue(LinkQueue* LQ, DataType* data) {
  65. QNode** prev = NULL, * prev_node = NULL;//保存当前已选举的最高优先级节点上一个节点的指针地址。
  66. QNode * last = NULL, *tmp = NULL;
  67. if (!LQ || IsEmpty(LQ)) {
  68. cout << "队列为空!" << endl;
  69. return 0;
  70. }
  71. if (!data) return 0;
  72. //prev 指向队头 front 指针的地址
  73. prev = &(LQ->front);
  74. printf("第一个节点的优先级: %d\n", (*prev)->priority);
  75. last = LQ->front;
  76. tmp = last->next;
  77. while (tmp) {
  78. if (tmp->priority > (*prev)->priority) {
  79. printf("抓到个更大优先级的节点[priority: %d]\n",
  80. tmp->priority);
  81. prev = &(last->next);
  82. prev_node = last;
  83. }
  84. last = tmp;
  85. tmp = tmp->next;
  86. }
  87. *data = (*prev)->data;
  88. tmp = *prev;
  89. *prev = (*prev)->next;
  90. delete tmp;
  91. LQ->length--;
  92. //接下来存在 2 种情况需要分别对待
  93. //1.删除的是首节点,而且队列长度为零
  94. if (LQ->length == 0) {
  95. LQ->rear = NULL;
  96. }
  97. //2.删除的是尾部节点
  98. if (prev_node && prev_node->next == NULL) {
  99. LQ->rear = prev_node;
  100. }
  101. return 1;
  102. }
  103. //打印队列中的各元素
  104. void PrintQueue(LinkQueue * LQ){
  105. QueuePtr tmp;
  106. if (!LQ) return;
  107. if (LQ->front == NULL) {
  108. cout << "队列为空!";
  109. return;
  110. }
  111. tmp = LQ->front;
  112. while (tmp){
  113. cout << setw(4) << tmp->data << "[" << tmp->priority << "]";
  114. tmp = tmp->next;
  115. }
  116. cout << endl;
  117. }
  118. //获取队首元素,不出队
  119. int GetHead(LinkQueue* LQ, DataType* data){
  120. if (!LQ || IsEmpty(LQ)){
  121. cout << "队列为空!" << endl;
  122. return 0;
  123. }
  124. if (!data) return 0;
  125. *data = LQ->front->data;
  126. return 1;
  127. }
  128. //清空队列
  129. void ClearQueue(LinkQueue* LQ){
  130. if (!LQ) return;
  131. while (LQ->front) {
  132. QueuePtr tmp = LQ->front->next;
  133. delete LQ->front;
  134. LQ->front = tmp;
  135. }
  136. LQ->front = LQ->rear = NULL;
  137. LQ->length = 0;
  138. }
  139. //获取队列中元素的个数
  140. int getLength(LinkQueue* LQ) {
  141. if (!LQ) return 0;
  142. return LQ->length;
  143. }
  144. int main(){
  145. LinkQueue* LQ = new LinkQueue;
  146. DataType data = -1;
  147. //初始化队列
  148. InitQueue(LQ);
  149. //入队
  150. for (int i = 0; i < 5; i++) {
  151. EnterQueue(LQ, i + 10, i);
  152. }
  153. //打印队列中的元素
  154. printf("队列中的元素(总共%d 个):", getLength(LQ));
  155. PrintQueue(LQ);
  156. cout << endl;
  157. //出队
  158. for (int i = 0; i < 5; i++) {
  159. if (DeleteQueue(LQ, &data)) {
  160. cout << "出队的元素是:" << data << endl;
  161. }
  162. else {
  163. cout << "出队失败!" << endl;
  164. }
  165. }
  166. //打印队列中的元素
  167. printf("出队五个元素后,队列中剩下的元素[%d]:\n", getLength(LQ));
  168. PrintQueue(LQ);
  169. cout << endl;
  170. ClearQueue(LQ);
  171. cout << "清空队列!\n";
  172. PrintQueue(LQ);
  173. //清理资源
  174. delete LQ;
  175. system("pause");
  176. return 0;
  177. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/551856
推荐阅读
相关标签
  

闽ICP备14008679号