数据结构——队列(C语言的实现)

什么是队列?

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出

FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

从图可知,队列其实可以用数组实现,也可以用链表实现,但是如果用数组,在队头删除数据的时候,会比较麻烦,所以此文章是以链表为基础进行队列的实现。

队列的的结构体定义和函数声明

typedef int QDataType;
typedef struct QueueNode //整体框架,一个元素的结构
{
	struct QueueNode* next;//结构体指针内又存放着其他数据,为单链表
	QDataType data;
}QNode;

//内部结构 
typedef struct Queue//队列更适合用链式结构去实现,队列的结构
{
	QNode* phead;//出数据 用QNode修饰,那么说明phead也可以指向下一个元素next和储存data
	QNode* ptail;//入数据
	int size;//记录大小,虽然链表没有大小限制,但是可以方便读取大小,不需要遍历
}Queue;

//为什么不用二级指针——指针放在结构体内,改变结构体,指针是结构体的成员,并不是结构体指针
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);//头删
bool QueueEmpty(Queue* pq);
QDataType QueueFront(Queue* pq);//取头部
QDataType QueueBack(Queue* pq);//取队尾
int QueueSize(Queue* pq);

需要注意的是

1.队列是一个整体,但是内部又是一个个由指针定义起来的节点。所以我们需要定义两个结构体,一个是队列的结构,一个是元素节点的结构。

2.队列尽管是一个整体,但是其内部的头尾指针终究还是节点,所以内部的指针还是用节点的结构体指针来定义。

队列元素的插入

我们知道是“FIFO"结构,所以要是插入数据,那么就只能在队列的尾部进行插入。

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);//整体断言

	QNode* newnode = (QNode*)malloc(sizeof(QNode));//建立一个空的
	if (newnode == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	newnode->data = x; // 如果新建的是空,说明是第一个元素
	newnode->next = NULL;
	if (pq->ptail == NULL)//第一个元素
	{
		assert(pq->phead==NULL);//头尾部断言

		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;//成为新的尾部
	}
	pq->size++;
}

代码中有两个结构体指针变量,一个是“Queue*” ;另一个是"QNode*" 

我们对于结构体,改变的是整个结构体,所以传入的应该是结构体,用“Queue*"来修饰

但是建立节点,就要用节点的结构体来定义“QNode*”来修饰。

队列元素的删除

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

	//1.一个节点,直接释放
	if (pq->phead->next == NULL)
	{
		free(pq->phead);//一个节点直接释放
		pq->phead = pq->ptail = NULL;
	}
	else//多个结点,头删
	{
		QNode* next = pq->phead->next;
		free(pq->phead);//头部往后
		pq->phead = next;//释放后再更新头部的位置
	}
	pq->size--;
}

取队头和队尾元素

此处本来不能取尾的,但还是给出来代码吧。

QDataType QueueFront(Queue* pq)//取头部
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->phead->data;
}
QDataType QueueBack(Queue* pq)//取队尾
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->ptail->data;
}

队列的元素个数

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

	return pq->size;//返回元素个数
}

队列的初始化

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

	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

队列的删除

void QueueDestroy(Queue* pq)
{
	assert(pq);
	//第一个元素就是Queue中的phead,同时也是QNode的初始指针位置
	QNode* cur = pq->phead;//用结构体指针定义的cur遍历指针,故直接作用于phead
	while (cur)//处理中间的指针,中间释放内存,头尾要置空
	{
		QNode* next = cur->next;
		free(cur);
		cur=next;
	}
	pq->phead = pq->ptail = NULL;//头尾也要变为NULL
	pq->size = 0;
}

队列的删除也就是一个个指针节点的删除,释放内存后即可。

判断队列是否为空

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;//为空,那么元素数为0,否则不为0
}

队列的实现的底层是链表,难点在于两个结构体的构建,一个是节点的结构体构建,而且节点要有next指针指向下一个元素,队列结构的结构体,需要有一个头指针和尾指针,而且这两个指针也是要由节点的结构体来构建的。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值