声明:
本文章是基于链表实现的队列,推荐对链表有一定了解基础的朋友阅读。本文作者小白一枚,所述内容仅供参考,文章中若存在错误欢迎各路大佬指正。
不熟悉链表的朋友可以参考文章:数据结构:单链表的相关操作-CSDN博客
队列的基本结构:
中间的数据节点,可以认为就是一个“链表”,但这个“链表”不能像一般链表那样在任意位置自由增删查改。
这些节点的定义方式和链表中涉及的节点一样,包含数据域和指针域。
节点的结构:
队列的数据结构定义:
节点结构体:队列中包含多个节点,所以我们需要定义一个节点的结构体,节点结构体中包含节点的信息,即数据域和指针域。
队列结构体:需要定义一个队列的结构体,方便实例化一个队列。队列结构体中包含两个指针,头指针和尾指针,这两个指针是队列初始化、出入队等的操作基石。
上面这两点就像老师和学生的结构体关系一样,有很多老师,一个老师一般又会管很多学生。这里的老师就是一个队列,学生就是一个队列中的许多节点。
上述两种结构体定义源码:
typedef struct Node //创建节点
{
int data;
struct Node* next;
}Node;
typedef struct Queue
{
Node* front; //头指针
Node* rear; //尾指针
}Queue;
队列的初始化:
初始化就是将两个指针先置空
void init(Queue* q) //队列的初始化
{
q->front = NULL;
q->rear = NULL;
}
检测队列是否为空:
因为队列中,数据只能从头部弹出,所以检测一个队列是否为空,只需要检验队列的头指针front的指向是否为空即可,若其为空,说明队列为空。
int isempty(Queue* q)
{
return q->front == NULL;
}
入队操作:
这里分两种情况:
(1)入队元素是第一个节点,那么需要将头指针和尾指针均指向该节点即可。
(2)入队元素不是第一个节点,则头指针不变,需要先将rear指向的节点和新节点关联起来,即rear->next = newnode;然后在将rear指针重新指向队列末尾,即rear->newnode。
总之,需要始终保证front指向头节点,rear指向尾节点。
void enqueue(Queue* q, int dight) //入队操作 队尾入,队头出
{
Node* newnode = (Node*)malloc(sizeof(Node));
if (!newnode)
{
printf("创建新节点失败!");
exit(EXIT_FAILURE);
}
newnode->next = NULL;
newnode->data = dight;
//注意这里的q和main函数中的q含义是不一样的,这里的q已经是一个结构体指针了,所以在传入enpty()时直接传入
//而main函数中实例化的一个q只是queue类型的一个变量,需要使用取址符&传入
//不要写成了 if (isempty(&q))
if (isempty(q))
{
q->front = newnode;
q->rear = newnode; //将两个指针均指向第一个进来的节点
}
else
{
q->rear->next = newnode; //这里其实是将之前最后的节点的Next指向newnode
q->rear = newnode; //这里是重新将rear指针指向最后一个节点
}
}
出队操作:
头部出队,只需要先检验是否为空,若不为空,则front指针后移一位,然后释放之前front指针指向的节点即可。
int dequeue(Queue* q) //出队
{
if (isempty(q))
{
printf("队列为空!\n");
return -1;
}
else
{
Node* temp = q->front;
q->front = temp->next;
int item = temp->data;
free(temp);
return item;
}
}
完整源码:
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
typedef struct Node //创建节点
{
int data;
struct Node* next;
}Node;
typedef struct Queue
{
Node* front; //头指针
Node* rear; //尾指针
}Queue;
void init(Queue *q) //队列的初始化
{
q->front = NULL;
q->rear = NULL;
}
int isempty(Queue* q)
{
return q->front == NULL;
}
void enqueue(Queue * q,int dight) //入队操作 队尾入,队头出
{
Node* newnode = (Node*)malloc(sizeof(Node));
if (!newnode)
{
printf("创建新节点失败!");
exit(EXIT_FAILURE);
}
newnode->next = NULL;
newnode->data = dight;
//注意这里的q和main函数中的q含义是不一样的,这里的q已经是一个结构体指针了,所以在传入enpty()时直接传入
//而main函数中实例化的一个q只是queue类型的一个变量,需要使用取址符&传入
//不要写成了 if (isempty(&q))
if (isempty(q))
{
q->front = newnode;
q->rear = newnode; //将两个指针均指向第一个进来的节点
}
else
{
q->rear->next = newnode; //这里其实是将之前最后的节点的Next指向newnode
q->rear = newnode; //这里是重新将rear指针指向最后一个节点
}
}
int dequeue(Queue * q) //出队
{
if (isempty(q))
{
printf("队列为空!\n");
return -1;
}
else
{
Node* temp = q->front;
q->front = temp->next;
int item = temp->data;
free(temp);
return item;
}
}
int main()
{
Queue q;
init(&q);
enqueue(&q, 3);
enqueue(&q, 2);
enqueue(&q, 1);
//printf("第一次出队:%d\n", dequeue(&q));
//printf("第二次出队:%d\n", dequeue(&q));
//printf("第三次出队:%d\n", dequeue(&q));
//printf("第四次出队:%d\n", dequeue(&q));
while (q.front != NULL)
{
printf("%d\n", dequeue(&q));
}
return 0;
}