队列(Queue)是一种先进先出(First In First Out, FIFO)的线性数据结构。以下是关于队列的详细解释:
队列的基本概念
-
先进先出(FIFO):队列中的元素,最先被插入(enqueue)的,最先被取出(dequeue)。
-
队头与队尾:队列有两个端点,队头(front)和队尾(rear)。队头是元素被取出的位置,队尾是元素被插入的位置。
队列的物理实现
队列可以使用数组或链表来实现:
- 数组实现:使用一个固定大小的数组来存储队列元素,并维护两个指针(或索引)分别指向队头和队尾。
- 链表实现:使用链表节点来存储队列元素,每个节点包含数据和指向下一个节点的指针。队列使用两个指针分别指向链表的头节点和尾节点。
队列的基本操作
以下为队列的主要操作:
- 初始化(Init):创建一个空队列。
- 入队(Enqueue):在队尾插入一个新元素。
- 出队(Dequeue):移除队头的元素。
- 查看队头元素(Front):返回队头元素的值,但不移除它。
- 判断队列是否为空(IsEmpty):检查队列是否不包含任何元素。
- 判断队列是否满(IsFull):仅在固定大小的队列中需要,检查队列是否达到其容量限制。
队列的操作示例
以下是使用数组实现的队列的操作示例:
初始化
#define MAX_SIZE 100
typedef struct Queue {
int data[MAX_SIZE];
int front;
int rear;
} Queue;
void initQueue(Queue *q) {
q->front = 0;
q->rear = 0;
}
入队
bool enqueue(Queue *q, int value) {
if ((q->rear + 1) % MAX_SIZE == q->front) {
// 队列满,无法入队
return false;
}
q->data[q->rear] = value;
q->rear = (q->rear + 1) % MAX_SIZE; // 环形队列的队尾指针移动
return true;
}
出队
bool dequeue(Queue *q, int *value) {
if (q->front == q->rear) {
// 队列空,无法出队
return false;
}
*value = q->data[q->front];
q->front = (q->front + 1) % MAX_SIZE; // 环形队列的队头指针移动
return true;
}
查看队头元素
bool front(Queue *q, int *value) {
if (q->front == q->rear) {
// 队列空,无法查看队头元素
return false;
}
*value = q->data[q->front];
return true;
}
判断队列是否为空
bool isEmpty(Queue *q) {
return q->front == q->rear;
}
判断队列是否满
bool isFull(Queue *q) {
return (q->rear + 1) % MAX_SIZE == q->front;
}
队列的应用
队列在计算机科学中有广泛的应用,以下是一些例子:
- 任务调度:操作系统使用队列来管理任务和进程。
- 缓冲处理:在网络中,队列用于缓冲数据包。
- 广度优先搜索(BFS):在图论中,队列用于广度优先搜索算法。
- 打印队列:打印任务通常在队列中等待,按照到达顺序进行处理。
队列的优缺点
优点:
- 插入和删除操作的时间复杂度为O(1),效率高。
- 实现简单。
缺点:
- 固定大小的队列可能导致空间浪费或不足。
- 链表实现的队列需要额外的内存来存储节点间的指针。
代码示例
循环队列
#include <stdio.h>
#include <stdlib.h>
#define N 10
typedef int data_t;
typedef struct seq // 循环队列结构体
{
data_t data[N]; // 循环队列存储数据的数组
int head; // 队头元素下标
int tail; // 队尾元素下标
} seq_t, *seq_p;
// 创建空队列
seq_p create_sequeue()
{
seq_p p = (seq_p)malloc(sizeof(seq_t)); // 开辟循环队列大小空间
if (NULL == p)
{
perror("malloc err"); // perror打印上一个函数报的错误
return NULL; // 错误情况让函数返回空指针
}
// 对结构体初始化
p->head = 0;
p->tail = 0;
return p;
}
// 判满
int full_qeuqeu(seq_p p)
{
return (p->tail + 1) % N == p->head;
}
// 入队
void push_queue(seq_p p, int data)
{
if (full_qeuqeu(p))
{
printf("full\n");
}
p->data[p->tail] = data;
p->tail = (p->tail + 1) % N;
}
// 判空
int null_qeuqeu(seq_p p)
{
return p->tail == p->head;
}
// 出队
int pop_queue(seq_p p)
{
if (null_qeuqeu(p))
{
printf("null\n");
}
int i = p->head;
while (i != p->tail)
{
printf("%d ", p->data[i]);
i = (i + 1) % N;
}
printf("\n");
}
// 求长度
int len_queque(seq_p p)
{
return (p->tail - p->head + N) % N;
}
int main(int argc, char const *argv[])
{
seq_p p = create_sequeue();
int i = 0, num;
while (scanf("%d", &num) != EOF)
{
push_queue(p, num);
}
pop_queue(p);
printf("len:%d\n", len_queque(p));
return 0;
}
链式队列
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
typedef struct node // 链式队列结构体
{
data_t data;
struct node *next;
} node_t, *node_p;
typedef struct linkqueue // 将队列的头尾指针封装成一个结构体
{
node_p head; // 队列的头指针
node_p tail; // 队列的尾指针
} linkqueue_t, *linkqueue_p;
// 创建一个空的队列,用有头链表
linkqueue_p create_linkqueue()
{
// 开辟队列结构体大小空间
linkqueue_p p = (linkqueue_p)malloc(sizeof(linkqueue_t));
if (NULL == p)
{
perror("error");
return NULL;
}
// 初始化队列结构体, 让头尾指针都指向开辟的头节点
p->head = p->tail = (node_p)malloc(sizeof(node_t));
if (NULL == p->head)
{
perror("p->front malloc err");
return NULL;
}
// 初始化头节点
p->head->next = NULL;
return p;
}
// 入队
int push_linkqueue(linkqueue_p p, int data)
{
// 新建节点,保存入队数据
node_p new = (node_p)malloc(sizeof(node_t));
if (NULL == new)
{
perror("new error");
return -1;
}
new->data = data; // 将数据插入新节点数据域
new->next = NULL; // 新节点指针域置空
p->tail->next = new; // 将新节点尾插到链表
p->tail = new; // 移动尾指针到新节点 让新结点成为尾节点
return 0;
}
// 出队
int pop_linkqueue(linkqueue_p p)
{
if (p->head == p->tail)//判空
{
printf("null\n");
}
node_p del = NULL;
while (p->head->next != NULL)
{
del = p->head;//定义del保存当前头节点
// printf("%d ", del->data);
p->head = del->next;//将头指针向后移动
free(del);//释放pdel
printf("%d ", p->head->data);//将要出队数据输出
}
printf("\n");
}
//计算长度
int len_linkqueue(linkqueue_p p)
{
int len=0;
node_p q=p->head->next;
while(q != NULL)
{
len++;
q=q->next;
}
return len;
}
int main(int argc, char const *argv[])
{
linkqueue_p p = create_linkqueue();
int num;
while (scanf("%d", &num) != EOF)
{
push_linkqueue(p, num);
}
// node_p h = p->head;
// while (h->next != NULL)
// {
// h = h->next;
// printf("%d ", h->data);
// }
// printf("\n");
printf("%d\n",len_linkqueue(p));
pop_linkqueue(p);
return 0;
}