【数据结构】队列及其实现

目录

1.队列的概念及结构

2.队列的实现

2.1队列结构定义 

2.2队列的初始化及销毁

2.3数据入队

2.4数据出队

2.5访问队头数据

2.6访问队尾数据

2.6判断队列是否为空

2.7求队列的大小

2.7打印队列 


1.队列的概念及结构

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

队列中先进先出FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

【数据结构】队列及其实现_第1张图片

2.队列的实现

队列结构可以使用数组和链表结构实现,但一般采用的是链表,因为对于数组结构,队头出数据的效率较低

2.1队列结构定义 

使用链表实现队列,队列中的每个元素都是节点的形式,所以需要定义节点的结构

对于队列,其具有队尾入数据,队头出数据的特性,所以其结构定义需要两个指针,分别指向队头和队尾

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;

2.2队列的初始化及销毁

初始化即队列为空队列,队头指针和队尾指针都指向空

销毁队列,即释放队列中所有节点的空间,队头指针和队尾指针重新指向空

//队列初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}
//队列销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* del = cur;
		cur = cur->next;
		free(del);
	}
	pq->head = pq->tail = NULL;
}

2.3数据入队

队列结构中,数据入队从队尾入,需要考虑空队列和非空队列两种情况

1️⃣空队列:

【数据结构】队列及其实现_第2张图片2️⃣非空队列:

【数据结构】队列及其实现_第3张图片

 空队列和非空队列不同的是空队列插入数据时需要更新队头指针

//数据入队
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	//空队列时插入
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	//非空队列时插入
	else
	{
		pq->tail->next = newnode;//链接新元素
		pq->tail = newnode;//更新队尾
	}
}

2.4数据出队

队列结构中,数据出队从队头出,对于空队列,出队操作非法

出队操作后,需要更新队头指针,并释放已出队节点的空间

【数据结构】队列及其实现_第4张图片

特殊情况:队列中只有一个节点

【数据结构】队列及其实现_第5张图片

//数据出队
void QueuePop(Queue* pq)
{
	assert(pq);
	//空队列不能进行出队操作
	assert(!QueueEmpty(pq));
	//队列中只有一个元素
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* del = pq->head;
		pq->head = pq->head->next;
		free(del);
		del = NULL;
	}
}

2.5访问队头数据

队头数据的访问操作在队列为空时非法,所以需要先断言,非空链表才可以进行队头数据的访问操作,通过队头指针访问即可

//访问队头数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;

}

2.6访问队尾数据

队尾数据的访问操作在队列为空时非法,所以需要先断言,非空链表才可以进行队尾数据的访问操作,通过队尾指针访问即可

//访问队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

2.6判断队列是否为空

队列为空则队头指针和队尾指针都指向空,可以使用if-else语句进行返回

也可以参考以下代码,直接返回pq->head == NULL && pq->tail == NULL,只有当pq->head和pq->tail同时为NULL是才返回真,即队列为空

Note:

判空函数的返回类型为bool,但是C语言标准中没有bool类型,所以需要我们自己定义

#define bool int
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	/*if (pq->tail == pq->head == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}*/
	return pq->head == NULL && pq->tail == NULL;
}

2.7求队列的大小

求队列的大小,遍历统计节点个数并返回即可

//求队列的大小
int QueueSize(Queue* pq)
{
	assert(pq);
	int size = 0;
	QNode* cur = pq->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

2.7打印队列 

为了便于观察入队与出队操作,可以编写一个打印函数便于调试

//打印队列
void QueuePrint(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

你可能感兴趣的:(数据结构,数据结构,链表)