一、队列的基本概念
1.队列定义
队列是一种先进先出的线性表数据结构(First in First out),现实中的例子就是,排队购票,先排队的先购票,购完票之后直接从这个队中离开,后来的在这个队后面排队,这就是队列。
如图;
这就是一个空的队列,从队尾入队,从队头出队
2.常见的基本操作
- initQueue:初始化队列
- empty: 判断队列是否为空
- push:入队操作
- pop:出队操作
- Front:获取队头元素
3.数据结构定义
为了锻炼高度模块化(分层设计),这里我们直接嵌套,不在Queue中直接定义数组,而是重新抽象出一个独立的vector数据结构作为底层容器,让Queue通过组合的方式使用vector来实现其功能。这种设计强调关注点分离,将内存管理的职责交给vector模块,而Queue模块只需专注于队列特有的逻辑操作。
typedef struct Queue {vector* data;int size,head,tail;//size记录当前队列有多少元素
}Queue;
二、代码实现
首先引用头文件,宏定义队列的开始元素为多少,定义vector及Queue
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <stdbool.h>
#define BEGIN_SIZE 6
typedef struct vector {int* val;int size;//记录当前容量
}vector;
typedef struct Queue {vector* data;int size,head,tail;//size记录当前队列有多少元素
}Queue;
初始化Queue
Queue *initQueue() {Queue* q = (Queue*)malloc(sizeof(Queue));q->data = initVector();q->head = q->tail = q->size = 0;return q;
}
要想初始化Queue,那么也就要初始化vector
vector* initVector()
{vector * v=(vector*)malloc(sizeof(vector));v->size = BEGIN_SIZE;v->val = (int*)malloc(sizeof(int) * BEGIN_SIZE);return v;
}
这样队列的初始化就实现了,下来我们依次实现队列的基本功能:
- empty: 判断队列是否为空
- push:入队操作
- pop:出队操作
- Front:获取队头元素
empty():
bool empty(Queue* q) {return q->size == 0;//如果当前元素的个数等于 0 ,那么则证明队列为空
}
push():
int push(Queue* q, int val) {checkFull(q); /*如果队列已经满了,扩容队列*/q->data->val[q->tail++] = val;q->size++;return 1;
}
pop():
int pop(Queue* q) {if (empty(q))/*如果队列为空的话,则返回-1代表弹出失败*/ {printf("pop: 队列为空\n");return -1;}int count = 0;while (count < q->tail - 1) {q->data->val[count] = q->data->val[count + 1];count++;}q->tail--;q->size--;return 1;
}
解释下,这里为什么count<q->tail-1 为什么不是 count<q->tail
呢
例如,队列中有三个元素,那么tail的值就是3,count从0开始,一共要循环到3次,最后一次的count等于 2 ,这个时候 q->data->val[count] = q->data->val[count + 1];
这一句就会变为q->data->val[2] = q->data->val[3];
,此时 3 这个位置是tail的位置,在内存中并没有赋值,内存中的值是未定义的(可能是垃圾值)
Front():
int Front(Queue* q) {if (empty(q)) {printf("Front 队列为空\n");return -1;}return q->data->val[q->head];
}
反过头处理checkFull()
,检查队列是否为满,满的话则需要扩容
checkFull():
void checkFull(Queue *q) {if (q->size == q->data->size) {int newSize = q->data->size * 2;int * newVal=(int *)realloc(q->data->val, sizeof(int) * newSize);if (newVal == NULL) {printf("error checkFull\n");exit(-1);}q->data->val = newVal;q->data->size = newSize;}return;
}
查看队列所有元素
outAll():
void outAll(Queue* q) {printf("Queue: ");for (int i = q->head; i < q->tail; i++) {printf("%3d ", q->data->val[i]);}printf("\n");return;
}
最后释放内存
freeQueue():
void freeQueue(Queue* q) {freeVector(q->data);free(q);return;
}
freeVector():
void freeVector(vector* v) {free(v->val);free(v);return;
}
main函数(测试函数)
int main() {Queue* q = initQueue();//初始化一个队列pop(q);//在空队列时弹出,应该输出 pop: 队列为空Front(q);//在空队列时获取队头元素,应该输出 Front: 队列为空srand(time(NULL));
#define MAX_OP 10for (int i = 0; i < MAX_OP; i++) {int op = rand() % 5, val = rand() % 100;switch (op) {case 0://pop操作printf("front of queue %d 弹出此元素\n", Front(q));pop(q);break;case 1:case 2:case 3:case 4://push操作printf("将 %d push进队列\n", val);push(q, val);break;}outAll(q);}printf("队头元素为: %3d\n",Front(q));return 0;
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define BEGIN_SIZE 6
typedef struct vector {int* val;int size;//记录当前容量
}vector;
typedef struct Queue {vector* data;int size, head, tail;//size记录当前队列有多少元素
}Queue;
vector* initVector()
{vector * v=(vector*)malloc(sizeof(vector));if (v == NULL) {printf("error initVector\n");exit(-1);}v->size = BEGIN_SIZE;v->val = (int*)malloc(sizeof(int) * BEGIN_SIZE);return v;
}
Queue *initQueue() {Queue *q = (Queue*)malloc(sizeof(Queue));if (q == NULL) {printf("error initQueue\n");exit(-1);}q->data = initVector();q->head = q->tail = q->size = 0;return q;
}
bool empty(Queue* q) {return q->size == 0;
}
void checkFull(Queue *q) {if (q->size == q->data->size) {int newSize = q->data->size * 2;int * newVal=(int *)realloc(q->data->val, sizeof(int) * newSize);if (newVal == NULL) {printf("error checkFull\n");exit(-1);}q->data->val = newVal;q->data->size = newSize;}return;
}
int push(Queue* q, int val) {checkFull(q); /*如果队列已经满了,扩容队列*/q->data->val[q->tail++] = val;q->size++;return 1;
}int pop(Queue* q) {if (empty(q))/*如果队列为空的话,则返回-1代表弹出失败*/ {printf("pop: 队列为空\n");return -1;}int count = 0;while (count < q->tail - 1) {q->data->val[count] = q->data->val[count + 1];count++;}q->tail--;q->size--;return 1;
}int Front(Queue* q) {if (empty(q)) {printf("Front: 队列为空\n");return -1;}return q->data->val[q->head];
}void outAll(Queue* q) {printf("Queue: ");if (empty(q)) {printf("NULL\n");return;}for (int i = q->head; i < q->tail; i++) {printf("%3d ", q->data->val[i]);}printf("\n");return;
}void freeVector(vector* v) {free(v->val);free(v);return;
}void freeQueue(Queue* q) {freeVector(q->data);free(q);return;
}int main() {Queue* q = initQueue();//初始化一个队列pop(q);//在空队列时弹出,应该输出 pop: 队列为空Front(q);//在空队列时获取队头元素,应该输出 Front: 队列为空srand(time(NULL));
#define MAX_OP 10for (int i = 0; i < MAX_OP; i++) {int op = rand() % 5, val = rand() % 100;switch (op) {case 0://pop操作printf("front of queue %d 弹出此元素\n", Front(q));pop(q);break;case 1:case 2:case 3:case 4://push操作printf("将 %d push进队列\n", val);push(q, val);break;}outAll(q);}printf("队头元素为: %3d\n",Front(q));return 0;
}