队列简介
队列是一种先进先出FIFO,First-In-First-Out
的线性表,通常用链表或者数组来实现。队列只能在队尾插入元素,只能在队首删除元素。
队列,第一个元素叫做队首,最后一个元素叫做队尾。队首元素删除叫做出队,新元素加入队尾叫做入队。队列有一个很重要的性质,就是 先进先出,First In First Out(FIFO)。
我们在构造队列时,需要用两个变量来记录队首和队尾的位置,设置这两个变量有利于我们去维护队列的次序性。
循环队列
只记录头尾的数组队列容易造成假溢出,当记录尾部位置的tail
达到队列的上限后就不能再插入了,此时再插入就意味着溢出。但是tail
达到上限后并不是要插入的元素真的“无处可放”了。为了解决这种问题,我们用数组实现队列的方式均是以“循环队列”的方式实现的。
循环队列,顾名思义,就是以循环的方式来存储队列。当队尾标记tail
到达队列上限后,如果队列内的元素没有达到上限,就跳转到数组的开始位置,也就是 0 的位置,队首标记到达队列上限也采取同样的处理。通过这样的方法,我们就能够最大化利用内存空间,避免“假溢出”的情况出现。
用数组实现循环队列的基本操作
/*************************************************************************
> File Name: 3.queue.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年03月30日 星期二 09时31分56秒
> 数组实现循环队列的基本操作
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include <time.h>
typedef struct Queue{
int *data;
int head,tail,length,size;
}Queue;
/*
* 队列初始化
* @param n: 队列初始化大小
* */
Queue *init(int n) {
Queue *q = (Queue *)malloc(sizeof(Queue));
q->data = (int *)malloc(sizeof(int) * n);
q->head = q->tail = q->length;
q->size = n;
return q;
}
/*
* 判空
* @param q: 要操作的队列指针
* **/
int empty(Queue *q) {
return q->length == 0; // 判断队列长度是否为零
}
/*
* 扩容
* @param q: 要操作的队列指针
* */
int expand(Queue *q) {
if(q == NULL) return 0;
int extr_size = q->size;
int *p = NULL;
while(extr_size) { // 空间使用过大,可能造成申请失败
p = (int *)malloc(sizeof(int) * (q->size + extr_size));
if(p) break;
extr_size >>= 1; // 扩容大小减半
}
if(p == NULL) return 0;
for(int j = 0; j < q->length; j++) p[j] = q->data[(q->head + j) % q->size];
free(q->data);
q->data = p;
q->head = 0;
q->tail = q->length;
q->size += extr_size;
}
/*
* 入队
* @param q: 要操作的队列指针
* @param val: 要入队的新元素值
* */
int push(Queue *q, int val) {
if(q == NULL) return 0; // 判断队列是否存在
if(q->tail == q->length && !expand(q)) return 0;// 队列已满且扩容失败
q->data[q->tail++] = val;
if(q->tail == q->size) q->tail = 0; // tail值达到size时赋值为0
// q->tail = q->tail % q->size;
q->length++;
return 1;
}
/*
* 出队
* @param q: 要操作的队列指针
* */
int pop(Queue *q) {
if(q == NULL || empty(q)) return 0; // 队列不存在或者为空
q->head++;
if(q->head == q->size) q->head = 0; // head值达到size值时赋值为0
// q->head = q->head % q->size;
q->length--;
return 1;
}
/*
* 获得队首元素值
* @param q: 要操作的队列指针
* */
int front(Queue *q) {
return q->data[q->head];
}
/*
* 队列销毁
* @param q: 要操作的队列指针
* */
void clear(Queue *q) {
if(q == NULL) return;
free(q->data);
free(q);
}
/*
* 打印队列
* @param q: 要操作的队列指针
* */
void output(Queue *q) {
printf("Queue:[");
int i = q->head;
do{
printf("%d ", q->data[i]);
i = (i + 1) % q->size;
}while(i != q->tail);
printf("]\n");
}
int main() {
srand(time(0));
#define MAX_OP 20
Queue *q = init(MAX_OP);
for(int i = 0; i < MAX_OP; i++) {
int op = rand() % 4;
int val = rand() % 100;
if(op) printf("push %d to Queue = %d\n", val, push(q, val));
else if(!empty(q)) printf("%d pop out from Queue", front(q)),printf(" = %d\n",pop(q));
else printf("fail to pop a item!\n");
output(q),printf("\n");
}
clear(q);
#undef MAX_OP
return 0;
}
链表实现队列的基本操作
/*************************************************************************
> File Name: 3.queue_link.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年03月30日 星期二 10时26分51秒
> 用链表实现队列
************************************************************************/
#include<stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node {
int data;
struct Node *next;
}Node;
typedef struct Queue {
int length;
Node *head, *tail;
}Queue;
/*
* 获取一个赋值结点
* @param val: 新节点的值
* */
Node *getNode(int val){
Node *node = (Node *)malloc(sizeof(Node));
node->data = val;
node->next = NULL;
return node;
}
/*
* 初始化队列
* */
Queue *init() {
Queue *q = (Queue *)malloc(sizeof(Queue));
q->length = 0;
q->head = NULL;
q->tail = NULL;
return q;
}
/*
* 队列判空
* @param q: 待处理队列的指针
* **/
int empty(Queue *q) {
return q->length == 0;
}
/*
* 入队
* @param q: 待处理队列的指针
* @param val: 待入队元素的值
* */
int push(Queue *q, int val) {
if(q == NULL) return 0;
if(empty(q)){
q->tail = getNode(val);
q->head = q->tail;
}else {
q->tail->next = getNode(val);
q->tail = q->tail->next;
}
q->length++;
return 1;
}
/*
* 出队
* @param q: 待处理队列的指针
* */
int pop(Queue *q) {
if(q == NULL || empty(q)) return 0;
Node *delete_node = q->head;
q->head = q->head->next;
if(q->head == NULL) q->tail = NULL;
free(delete_node);
q->length--;
return 1;
}
/*
* 获取队首元素值
* @param q: 待处理队列的指针
* */
int front(Queue *q) {
return q->head->data;
}
/*
* 清理队列
* @param q: 待处理队列的指针
* */
void clear(Queue *q) {
if(q == NULL) return;
while(q->head) {
Node *delete_node = q->head;
q->head = q->head->next;
free(delete_node);
}
free(q);
}
/*
* 队列打印
* @param q: 待处理队列的指针
* */
void output(Queue *q) {
printf("Queue:[");
Node *p = q->head;
while(p) {
printf("%d ",p->data);
p = p->next;
}
printf("]\n");
}
int main() {
srand(time(0));
#define MAX_OP 10
Queue *q = init();
for(int i = 0; i < MAX_OP; i++) {
int val = rand() % 100;
int op = rand() % 4;
if(op) printf("push %d to Queue = %d\n", val, push(q, val));
else if(!empty(q)) printf("%d pop out from Queue", front(q)),printf(" = %d\n",pop(q));
else printf("fail to pop a item!\n");
output(q),printf("\n");
}
clear(q);
#undef MAX_OP
return 0;
}
队列在做题过程中的简单实现
/*************************************************************************
> File Name: 3.queue_temp.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年03月30日 星期二 11时00分14秒
队列在刷题过程中的简单实现
************************************************************************/
#include<stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_OP 20
int queue[MAX_OP];
int head, tail;
/*
* 打印队列
* (为了查看方便,时间操作中并不需要)
* */
void output() {
printf("Queue:[");
for(int i = head; i < tail; i++) printf("%d ", queue[i]);
printf("]\n");
}
int main() {
srand(time(0));
for(int i = 0; i < MAX_OP; i++) {
int val = rand() % 100;
int op = rand() % 4;
if(op) { // 入栈操作
queue[tail++] = val;
printf("push %d to Queue = %d\n", val, 1);
}else { // 出栈操作
printf("%d pop out from Queue = 1\n", queue[head++]);
}
output(),printf("\n");
}
return 0;
}