数据结构——队列的实现(细就完事了)

1.队列

1.1队列的概念和结构

今天我们要是实现的队列是完全相反的,队列是数据先进先出而在中我们使用的顺序表(数组)来实现的。而队列却用单链表来实现是更加合适的。

队列:只允许在一端进行插入数据操作,在另一端进行数据操作的特殊线性表,队列具有先进先出FIFO(Frist in First out)。

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

数据结构——队列的实现(细就完事了)_第1张图片

 这里我们举个例子:在我们食堂买饭的时候,你付完钱商家都会给你一个号码,等叫到你号时就可以去领饭,以免被人插队,先买的就会先被叫到号,而队列就是秉持这样一个原则,先入先出的性质。

数据结构——队列的实现(细就完事了)_第2张图片

 由于队列要进行尾插头删操作,所以我们可以再定义一个结构体来保存队列的头指针和尾指针。队列的大小最好也保存一下。因为我们想要进行入队列出队列操作时,只需要通过队列的头指针和尾指针就可以进行尾插头删操作。


下面上代码讲解:

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

2.1 初始化和销毁队列

这里我们实现的单链表无头不循环的单链表所以我们把队列头和队列尾初始化为空指针。

而队列的销毁跟我们之前所学的都是一样的,每次记录下一个头节点位置,把头节点释放掉,直到为空为止。

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

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

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

2.2 队列的尾入

这里我们分两种情况:

第一种:第一次尾入数据的时候,新节点就是队列的尾和队列的头,把新结点赋值给队列的头和队列的尾

第二种:队列已经有数据了,我们把新的结点链接到尾后面,然后再把新结点赋值为新的结点,也就是更新队列的尾。(就是尾插)

总结:队列头是一直不变的,队列尾入一个数据就需要把队列尾往后面移动一位。

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		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++;
}

2.3 出队列

这里面我们分两种情况:

  • 当队列只有一个结点的时候,直接free掉第一个结点即可,然后把队列头和对列尾赋值尾空即可。
  • 当队列有两个及两个以上的结点的时候,我们先保存队列头的下一个结点,然后free掉队列头即可。

注意一下size要加1

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


	//1.一个节点
	//2.多个节点
	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--;
}

2.4 获得队列头元素和尾元素

这里是非常简单的直接返回我们头,尾指针指向节点存储的data数据就可以

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;
}

2.5 判断队列是否为空和获得队列元素个数

判断队列为空,只需要看它的大小是不是为0就行,或者判断队列的头指针和尾指针是不是都是空指针。

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

获得队列的元素个数,很简单,只需要返回队列的size就行

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

Queue.h

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

Queue.c

#include "Queue.h"


void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

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

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		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++;
}

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


	//1.一个节点
	//2.多个节点
	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;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

test.c

#include "Queue.h"

void TestQueue()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");

	QueueDestroy(&q);
}

int main()
{
	TestQueue();
	return 0;
}

以上就是今天分享队列的全部内容,如果喜欢的话请三联支持一下,我们下期再见

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