C语言:队列

声明:


本文章是基于链表实现的队列,推荐对链表有一定了解基础的朋友阅读。本文作者小白一枚,所述内容仅供参考,文章中若存在错误欢迎各路大佬指正。

不熟悉链表的朋友可以参考文章:数据结构:单链表的相关操作-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;
}

运行结果:

#include #include #include //队列最大长度 #define MAX_QUEUE 1024 //偷懒,就用静态队列了 static int mQueue[MAX_QUEUE]; //队列插入 void InsertData(int **Front, int **Rear) { if (*Rear + 1 == *Front && (*Rear + 1 - MAX_QUEUE != *Front)) { //当队列数据已满,返回 puts("Queue Size Overflow!\n"); return; } else if (*Rear - mQueue > MAX_QUEUE) { //实现的是类似循环队列,但由于是静态线性队列(数组) //而不是用链表来实现的,所以到静态队列(数组)尾部,尾指针自动指向(数组)头部 *Rear = mQueue; } puts("Input Data:"); scanf("%d", *Rear); //输入数据后,尾指针后移 *Rear += 1; } //从头指针删除一个队列中的数据 void DeleteData(int **Front, int **Rear) { if (*Front == *Rear) { //头指针尾指针重合,队列空,不能删除,返回 puts("Queue Empty!\n"); return; } else if (*Front - mQueue > MAX_QUEUE) { //参考 Rear *Front = mQueue; } //从头指针删除一个数据 *Front += 1; } //显示队列数据 void ShowData(int **Front, int **Rear) { int *temp; for (temp=*Front; temp!=*Rear; temp++) { printf("%d --> ", *temp); } puts("\n"); } void usage(void) { puts("1. Insert Data"); puts("2. Delete Data"); puts("3. Show Data"); } int main(int argc, char **argv) { //头指针,尾指针 //队列的一个特性 First in first out FIFO int *pFront, *pRear; int op_code; //初始化队列,头指针和尾指针此时指向的地址相同 pFront = pRear = mQueue; while (1) { usage(); scanf("%d", &op_code); switch (op_code) { case 1: printf("%p\n", pFront); printf("%d\n", *pFront); InsertData(&pFront, &pRear); break; case 2: DeleteData(&pFront, &pRear); break; case 3: ShowData(&pFront, &pRear); break; default: break; } } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值