一、队列的顺序储存结构
#include <stdlib.h> #include <stdio.h> #define MaxSize 10 //声明顺序队列 typedef struct { int data[MaxSize]; //存放队中元素 int front, rear; //队头和队尾指针 }SqQueue; //顺序队类型 //初始化队列 void InitQueue(SqQueue* &q) { q = (SqQueue*)malloc(sizeof(SqQueue)); q->front = q->rear = -1; } //销毁队列 void Destroy(SqQueue* &q) { free(q); } //判断队列是否为空 bool QueueEmpty(SqQueue* q) { if (q->front == q->rear) printf("这是一个空队列\n"); else printf("这不是一个空队列\n"); return (q->front==q->rear); } //判断队列是否为满 bool QueueFull(SqQueue* q) { if (q->rear == MaxSize - 1) printf("这个队列已经满了\n"); else printf("这个队列还没满\n"); return (q->rear == MaxSize - 1); } //进队列 bool enQueue(SqQueue* &q, int e) { if (q->rear == MaxSize - 1) return false; q->rear++; q->data[q->rear] = e; return true; } //出队列 bool deQueue(SqQueue* &q, int &e) { if (q->front == q->rear) return false; q->front++; e = q->data[q->front]; return true; } int main() { SqQueue* q; q = (SqQueue*)malloc(sizeof(SqQueue)); InitQueue(q); QueueEmpty(q); for (int i = 0; i < MaxSize; i++) { enQueue(q, i); } QueueEmpty(q); QueueFull(q); int a[MaxSize]; for (int i = 0; i < MaxSize; i++) { deQueue(q, a[i]); printf("%d ", a[i]); } printf("\n"); QueueEmpty(q); Destroy(q); return 0; }
二、环形队列
注:在前面的顺序队操作中,当rear==MaxSize-1时,队列中可能还有空位置,这种因为队满条件设置不合理而导致队满条件成立而队列中仍有空位置的情况称为假溢出。
可以看出,在出现假溢出时,队尾指针rear指向data数组的最大下标,而另外一端还有若干个位置 。解决的方法是把data数组的前端和后端连接起来,形成一个环形数组,把储存队列中的元素逻辑上看成一个环,称为环形队列或循环队列。
环形队列首尾相连后,当队尾指针rear=MaxSize-1后,再前进一个位置就到达0,于是就可以使用另一端的空位置储存元素了。
可以采用数学上的求余来操作rear和front指针:
队头指针 (front=front+1)% MaxSize 队尾指针 (rear=rear+1)% MaxSize
环形队列的队头和队尾指针初始值都置为0,显然队空条件是 q->rear==q->front,当进队元素的速度快于出对元素的速度时,队尾指针会很快赶上队头指针,此时,队满条件也是q->rear==q->front,这样无法区分队空队满了呀;
我们可以改为“队尾指针循环增1时等于队头指针”作为队满条件,也就是说尝试进队一次,若到达队头,就认为队满了,不能再进队。这样环形队就少用了一个元素空间,即该队列最多存储MaxSize-1个元素。
队空条件:q->rear=q->front
队满条件:(q->rear+1)==q->front
#include <stdlib.h> #include <stdio.h> #define MaxSize 10 //声明顺序队列 typedef struct { int data[MaxSize]; //存放队中元素 int front, rear; //队头和队尾指针 }SqQueue; //顺序队类型 //初始化队列 void InitQueue(SqQueue* &q) { q = (SqQueue*)malloc(sizeof(SqQueue)); q->front = q->rear = 0; } //销毁队列 void Destroy(SqQueue* &q) { free(q); } //判断队列是否为空 bool QueueEmpty(SqQueue* q) { if (q->front == q->rear) printf("这是一个空队列\n"); else printf("这不是一个空队列\n"); return (q->front == q->rear); } //判断队列是否为满 bool QueueFull(SqQueue* q) { if ((q->rear+1)%MaxSize == q->front) printf("这个队列已经满了\n"); else printf("这个队列还没满\n"); return ((q->rear + 1) % MaxSize == q->front); } //进队列 bool enQueue(SqQueue* &q, int e) { if ((q->rear+1)%MaxSize==q->front) //队满上溢出 return false; q->rear = (q->rear + 1) % MaxSize; q->data[q->rear] = e; return true; } //出队列 bool deQueue(SqQueue* &q, int &e) { if (q->front == q->rear) //队空下溢出 return false; q->front = (q->front + 1) % MaxSize; e = q->data[q->front]; return true; } int main() { SqQueue* q; q = (SqQueue*)malloc(sizeof(SqQueue)); InitQueue(q); QueueEmpty(q); for (int i = 0; i < MaxSize-1; i++) { enQueue(q, i); } QueueEmpty(q); QueueFull(q); int a[MaxSize]; for (int i = 0; i < MaxSize-1; i++) { deQueue(q, a[i]); printf("%d ", a[i]); } printf("\n"); QueueEmpty(q); Destroy(q); return 0; }
三、用单链表来实现链队,在表头删除(出队),在表尾插入(进队)
#include <stdio.h> #include <stdlib.h> //声明链栈数据结点 typedef struct qnode { int data; struct qnode* next; }DataNode; //声明链队头结点 typedef struct { DataNode* front; DataNode* rear; }LinkQuNode; //初始化链队 构造一个空队 创建一个链队结点 void InitQueue(LinkQuNode* &q) { q = (LinkQuNode*)malloc(sizeof(LinkQuNode)); q->front = q->rear = NULL; } //销毁链队 释放链队结点和所有数据结点 void DestroyQueue(LinkQuNode* &q) { DataNode* pre = q->front, *p; //pre指向队首结点 if (pre != NULL) { p = pre->next; //p指向pre的后续结点 while (p != NULL) { free(pre); pre = p; p = p->next; //退出循环 p->next=NULL } free(pre); //释放最后一个链队结点 } free(q); //释放链队结点 } //判断链队是否为空 bool QueueEmpty(LinkQuNode* q) { if (q->rear == NULL) printf("这是一个空队\n"); else printf("这不是空队哦\n"); return (q->rear == NULL); } //进队列 void enQueueNode(LinkQuNode* &q, int e) { DataNode* p; p = (DataNode*)malloc(sizeof(DataNode)); p->data = e; p->next = NULL; if (q->rear == NULL) //若链队为空,则新结点即是首结点,也是尾结点 { q->front = q->rear = p; } else { q->rear->next = p; //将结点p链到队尾 q->rear = p; //尾结点变成p } } //出队列 bool deQueueNode(LinkQuNode* &q, int &e) { DataNode *t; if (q->rear == NULL) return false; t = q->front; //t指向首结点 if (q->front == q->rear) //原队列只有一个数据结点时 q->front = q->rear = NULL; else //原队列有两个数据结点以上时 q->front = q->front->next; //q指向下一个元素 e = t->data; free(t); //释放队首元素 return true; } int main() { LinkQuNode* q; q = (LinkQuNode*)malloc(sizeof(LinkQuNode)); InitQueue(q); QueueEmpty(q); for (int i = 0; i < 10; i++) { enQueueNode(q,i); } QueueEmpty(q); int a[10]; for (int i = 0; i < 10; i++) { deQueueNode(q, a[i]); printf("%d ",a[i]); } printf("\n"); QueueEmpty(q); DestroyQueue(q); QueueEmpty(q); return 0; }以上是队列的声明定义方法,在后续章节再来写写应用吧。