队列的实现

  • 队列是一种特殊的顺序表,它遵循先进先出(First in First out)的原则,只能在一端插入数据,在另一端删除数据
  • 插入数据叫做入队,删除数据叫做出队
  • 插入数据的一端叫队尾,删除数据的一端叫队头

队列的实现_第1张图片队列的实现_第2张图片


队列的结构:

  • 如果用顺序表实现,入队还是比较方便,但出队就需要挪动数据了,显然不适合用顺序表实现

因此这里用链表实现队列

typedef int QDataType;

typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QueueNode;

但用链表还有一个问题,就是每次入队时还要遍历链表找尾指针,不是很方便

用双向循环链表是可以解决这个问题的,但是这里我们用另一种方法,那就是再定义一个结构体,里面存放链表的头指针和尾指针;
只要每次入队后更新一下尾指针,下次入队时就能轻易找到尾

同时加上一个size,用来记录当前队列的元素个数

因此,我们队列结构的最优解就是:

typedef int QDataType;

typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QueueNode;

typedef struct Queue
{
	QueueNode* phead;
	QueueNode* 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 QueueBack(Queue* pq);

//获取队头元素
QDataType QueueFront(Queue* pq);

//获取队列的元素个数
int QueueSize(Queue* pq);

初始化:

//初始化
void QueueInit(Queue* pq)
{
	assert(pq);

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

入队:

创建新结点:

QueueNode* CreateNewNode(QDataType x)
{
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newNode == NULL)
	{
		perror("CreateNewNode:malloc fail");
		exit(-1);
	}
	newNode->val = x;
	newNode->next = NULL;

	return newNode;
}
  • 如果队列为空,头指针和尾指针都要指向新结点
  • 如果队列不为空,尾指针指向新结点,更新尾指针
//入队
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QueueNode* newNode = CreateNewNode(x);

	if (pq->ptail == NULL)
	{
		pq->phead = newNode;
		pq->ptail = newNode;
	}
	else
	{
		pq->ptail->next = newNode;
		pq->ptail = newNode;
	}

    pq->size++;
}

出队:

  • 当队列为空,不能出数据,需要断言
  • 更新头指针,释放原来的头指针指向的空间
  • 如果只有一个结点,出队后,头指针为空并且原来头指针指向的空间已经释放,但是此时尾指针仍然指向原来头指针的位置,所以要置空
//出队
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->phead);

	QueueNode* cur = pq->phead;
	pq->phead = pq->phead->next;
	free(cur);

	if (pq->phead == NULL)
		pq->ptail = NULL;

	pq->size--;
}

判断队列是否为空:

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->phead == NULL;
}

获取队头元素:

  • 当队列为空时,不能获取元素
//获取队头元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);

	return pq->phead->val;
}

测试:

void TestQueue()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	while (!QueueEmpty(&q))
	{
		QDataType front = QueueFront(&q);
		printf("%d ", front);
		QueuePop(&q);
	}
	printf("\n");
}

队列的实现_第3张图片


获取队尾元素:

  • 队列为空,不能获取元素
//获取队尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);

	return pq->ptail->val;
}

获取队列元素个数:

//获取队列的元素个数
int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

销毁:

  • 遍历链表,销毁每个结点
  • 最后将头指针和尾指针置空,避免野指针
//销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);

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

需要源码的小伙伴可以去我的Gitee自行查看Queue/Queue · baiyahua/LeetCode - 码云 - 开源中国 (gitee.com)

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