[数据结构 -- C语言] 队列(Queue)

目录

1、队列

1.1 队列的概念及结构

2、队列的实现

2.1 接口

3、接口的实现

3.1 初始化队列

3.2 队尾入队列

分析:

3.3 队头出队列

分析:

3.4 获取队列头部元素

3.5 获取队列尾部元素

3.6 获取队列中有效元素个数

3.7 检测队列是否为空

3.7.1 int 类型判空

3.7.2 bool 类型判空

3.8 销毁队列

4、完整代码

5、效果展示


1、队列

1.1 队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

2、队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数
组头上出数据,效率会比较低。本篇文章就是用链表实现队列。

2.1 接口

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// 链式结构:表示队列 
typedef int QDataType;
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* front;
	QNode* rear;
	int size;
}Queue;

// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

3、接口的实现

3.1 初始化队列

我们将队头指针与队尾指针都置为 NULL,并将队列的大小赋值为 0。

void QueueInit(Queue* q)
{
	assert(q);

	q->front = NULL;
	q->rear = NULL;	
	q->size = 0;
}

3.2 队尾入队列

void QueuePush(Queue* q, QDataType data)
{
	assert(q);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail:");
		return;
	}
	newnode->data = data;
	newnode->next = NULL;

	if (q->rear == NULL)
	{
		assert(q->front == NULL);

		q->front = q->rear = newnode;
	}
	else
	{
		q->rear->next = newnode;
		q->rear = newnode;
	}
	q->size++;
}

分析:

我们是以链表实现队列的,所以每次入队的时候我们都要 malloc 一个 newnode 结点出来,将 newnode->data = data,newnode->next = NULL。

下来就是连接了:

我们要考虑这个结点是否是队列的第一个结点。

1、是队列的第一个结点的话,我们让头尾指针都指向这个结点(q->front = q->rear = newnode);

2、不是队列的第一个结点,我们将尾指针的next赋值为新节点(q->rear->next = newnode;), 再让尾指针指向新节点( q->rear = newnode;);

3、让队列的 size++。

3.3 队头出队列

void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	//1.一个结点
	if (q->front->next == NULL)
	{
		free(q->front);
		q->front = q->rear = NULL;
	}
	else//2.多个结点
	{
		QNode* next = q->front->next;
		free(q->front);
		q->front = next;
	}
	q->size--;
}

分析:

出队的时候要考虑队列是否是一个结点:

1、队列中只有一个结点,我们将这一个结点释放掉后(free(q->front)),将头、尾指针都置空(q->front = q->rear = NULL);

2、队列中有多个结点,那我们就将队头的下一个结点先保存起来(next = q->front->next),然后将队头释放掉(free(q->front)),最后让队头指向释放前队头的下一个结点(q->front = next);

3、最后让队列的 size--。

3.4 获取队列头部元素

取队头元素时,我们先要对队列进行判空,如果队列为空,那就不存在队头元素。

QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	return q->front->data;
}

3.5 获取队列尾部元素

取队尾元素时,我们先要对队列进行判空,如果队列为空,那就不存在队尾元素。

QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	return q->rear->data;
}

3.6 获取队列中有效元素个数

我们在创建队列的结构体时,在里面创建了一个变量 size,它专门记录队列中的元素个数,所以在这我们只要返回 q->size就可以了。如果没有定义 size 变量的话,我们遍历一遍队列,用计数器来统计一下个数也是可以的。

int QueueSize(Queue* q)
{
	assert(q);

	return q->size;
}

3.7 检测队列是否为空

3.7.1 int 类型接口

这里我们约定,为空返回非 0,非空返回 0。

int QueueEmpty(Queue* q)
{
	assert(q);

	if (0 == q->size)
		return 1;
	else
		return 0;
}

3.7.2 bool 类型接口

直接判断队头是否为空,队头为空队列就是空。

bool QueueEmpty(Queue* q)
{
	assert(q);

	return q->front == NULL;
}

3.8 销毁队列

销毁我们已经写的很多了,这就直接拿捏。我们先将单链表进行释放,这里有一个注意点,我们要先记下下一个位置,然后释放当前位置,然后将下个位置再交给当前位置来迭代。最后将头、尾指针置空,再将 size 置0。

void QueueDestroy(Queue* q)
{
	assert(q);

	QNode* cur = q->front;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->front = q->rear = NULL;
	q->size = 0;
}

4、完整代码

完整代码在代码仓库,入口:C语言: C语言学习的代码,多复习 - Gitee.com

5、效果展示

  • 31
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
C语言中没有内置的priority_queue数据结构。如果你想使用优先队列,你需要自己实现它或使用第三方库。 自己实现优先队列可以使用数组或链表来存储元素,并在插入和删除操作中保持元素的有序性。你可以使用堆的数据结构来实现这个目标。堆是一种完全二叉树,并且父节点的值总是大于或等于(最大堆)或小于或等于(最小堆)其子节点的值。 使用第三方库是更简单和常见的选择。一些常用的C语言库,如Glib(GNU C Library)、Libraries like Glib(GNU C Library)、libpqueue和libpq都提供了优先队列的实现。 下面是一个使用Glib库实现优先队列的示例: ```c #include <glib.h> int compare_int(gconstpointer a, gconstpointer b, gpointer user_data) { int value_a = *(int*)a; int value_b = *(int*)b; if (value_a > value_b) { return 1; } else if (value_a < value_b) { return -1; } else { return 0; } } int main() { GQueue* queue = g_queue_new(); int value1 = 42; int value2 = 11; int value3 = 78; // 插入元素到队列中 g_queue_insert_sorted(queue, &value1, compare_int, NULL); g_queue_insert_sorted(queue, &value2, compare_int, NULL); g_queue_insert_sorted(queue, &value3, compare_int, NULL); // 从队列中弹出元素 while (!g_queue_is_empty(queue)) { int* value = g_queue_pop_head(queue); printf("%d\n", *value); g_free(value); } g_queue_free(queue); return 0; } ``` 请注意,这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白在努力jy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值