前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言实现“队列“

C语言实现“队列“

作者头像
初阶牛
发布2023-10-14 17:34:27
2340
发布2023-10-14 17:34:27
举报
文章被收录于专栏:C语言基础

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯C语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:分享数据结构之C语言实现"队列".各个接口分别分析,讲解思路已经动图讲解. 金句分享: ✨书要好好读,喜欢的人也要好好争取!✨

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

在这里插入图片描述
在这里插入图片描述

用顺序表还是用链表实现队列比较好呢?

结构

尾插

头插

顺序表

效率很高,不需要移动数据

效率极低,需要移动除首元素以外的所有数据

链表

效率较低,需要遍历链表找尾巴

效率高,改变头指针即可

  1. 对于链表的缺点,我们可以额外创建一个尾指针用于记录尾结点.这样效率就不是问题了,而顺序表的头插是硬伤.
  2. 链表不需要扩容,顺序表需要动态扩容/

综上,咱还是选择链表=实现队列吧!

代码语言:javascript
复制
typedef int QDatatype;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}QNode;

typedef struct Queue
{
	QNode* head;//记录队首
	QNode* tail;//记录队尾
	int size;//记录长度
}Queue;

图解:

在这里插入图片描述
在这里插入图片描述

1.2 "队列"的常见接口:

接口介绍:

代码语言:javascript
复制
//队列的初始化操作
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestroy(Queue* pq);

//入队列
void QueuePush(Queue* pq, QDatatype x);
//出队列
void QueuePop(Queue* pq);
//队列的长度
int QueueSize(Queue* pq);
//队列是否为空
bool QueueEmpty(Queue* pq);
//取队头元素
QDatatype QueueFront(Queue* pq);
//取队尾元素
QDatatype QueueBack(Queue* pq);

二、接口的具体实现:

2.1 "队列"的"初始化"操作(QueueInit)

队列的结构是由两个结点指针,加一个记录长度的size变量组成.

队列的初始状态: 头指针=尾指针,长度为0.

代码:

代码语言:javascript
复制
//初始化"队列"操作
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
	int size = 0;
}

2.2 "入队"操作(QueuePush)

步骤:

  1. 申请一个结点,将数据域赋值为x(目标值),指针域指向NULL;
  2. 一般情况下,"入队"操作只影响尾指针.
  3. 链接:将尾指针指针域指向新节点.
  4. 更新尾指针(令尾指针本身指向新节点).

特殊情况:

第一个元素入队时,头指针尾指针都会收受到影响.需要将头指针尾指针都指向新节点.

在这里插入图片描述
在这里插入图片描述

特殊情况:

在这里插入图片描述
在这里插入图片描述

代码:

代码语言:javascript
复制
//入队列
void QueuePush(Queue* pq, QDatatype x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)//第一个元素入队列时,会影响头指针
	{
		pq->head = pq->tail = newnode;//将头指针和尾指针都指向新节点
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;//更新队尾
	}
	pq->size++;
	return 0;
}

2.3 "队列"判空(QueueEmpty)

如果头指针和尾指针都指向NULL则表示空队列

代码:

代码语言:javascript
复制
//队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	//如果头指针和尾指针都指向NULL则表示空队列
	if (pq->head == pq->tail && pq->tail == NULL)
	{
		return true;
	}
	return false;
}

2.4 “出队”(QueuePop)

步骤:

  1. 对于删除元素的"出队"操作,我们首先要进行"判空"操作.空队列不允许删除.
  2. 创建一个结点指针(Delete ):用于记录待会要出队的原队首结点.
  3. 将队首结点向后移动一步.(即将队首指针指向第二个元素).
  4. 释放Delete 结点.
  5. 长度(size)减少1;
在这里插入图片描述
在这里插入图片描述

特殊情况: 剩下最后一个待出队元素时: 会影响头指针,需要将头指针和尾指针都置空NULL;

这里就不画图了,相信聪明的友友们可以理解.

代码:

代码语言:javascript
复制
//出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QNode* Delete = pq->head;//记录原队首

	if (pq->head == pq->tail)//如果是最后一个元素出队列
	{
		pq->head = pq->tail = NULL;
	}
	else pq->head = pq->head->next;//更新队头指针
	free(Delete);//释放原队首
	pq->size--;
}

2.5 "队列"长度函数

这里采用了增加一个变量size用于记录队列的长度.所以直接返回size即可. 如果没有size就需要遍历.

代码语言:javascript
复制
//队列的长度
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

2.6 取"队头"和"队尾"元素

在创建队列时,我们已经分析了链式队列的结构,队首=和队尾元素我们可以直接通过队首指针(head)和队尾指针(tail)访问其数据域即可.

代码语言:javascript
复制
//取队头元素
QDatatype QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}

//取队尾元素
QDatatype QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);
	return pq->tail->data;
}

2.7 "队列"的销毁:

与链表的销毁类似: 步骤:

  1. 创建两个结点指针

(1):QNode* cur:从头指针开始,遍历整个队列 (2):QNode* next:用于记录下一个结点,方便cur被释放后,继续往下遍历.

  1. 释放cur指针指向的结点.
  2. 更新cur指针和next指针.
  3. 将队首指针(head)和队尾指针(tail)指向NULL.
  4. 将size置为0;

代码:

代码语言:javascript
复制
//队列的销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	QNode* next = cur;
	while (next)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

三、结语:

"栈"和"队列"都是很重要的一种数据结构,在计算机中有很多应用,后续会更新==“循环队列”==,和OJ题:用栈模拟队列,用队列模拟栈等. 如果文章对大家有帮助的话,牛牛会很开心的.💗💗💗

最后,小伙伴们的点赞就是给牛牛最大的支持,能不能给牛牛来一个一键三连呢?谢谢支持。

四、总代码:

4.1 主测试区(test.c)

代码语言:javascript
复制
#include"Queue.h"
int main()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	printf("队头数据%d\n", QueueFront(&q));
	printf("队头数据%d\n", QueueBack(&q));
	while (!QueueEmpty(&q))
	{
		printf("%d ", q.head->data);
		QueuePop(&q);
	}
	QueueDestroy(&q);;
	return 0;
}

4.2 接口实现区(Queue.c):

代码语言:javascript
复制
#include "Queue.h"

//队列的初始化操作
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
	int size = 0;
}



//入队列
void QueuePush(Queue* pq, QDatatype x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)//第一个元素入队列时,会影响头指针
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;//更新队尾
	}
	pq->size++;
	return 0;
}


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


//出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QNode* Delete = pq->head;//记录原队首

	if (pq->head == pq->tail)//如果是最后一个元素出队列
	{
		pq->head = pq->tail = NULL;
	}
	else pq->head = pq->head->next;//更新队头指针
	free(Delete);//释放原队首
	pq->size--;
}

//队列的长度
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//取队头元素
QDatatype QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}

//取队尾元素
QDatatype QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);
	return pq->tail->data;
}


//队列的销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	QNode* next = cur;
	while (next)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

4.3 接口声明区(Queue.h):

代码语言:javascript
复制
#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int QDatatype;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}QNode;

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

//队列的初始化操作
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestroy(Queue* pq);

//入队列
void QueuePush(Queue* pq, QDatatype x);
//出队列
void QueuePop(Queue* pq);
//队列的长度
int QueueSize(Queue* pq);
//队列是否为空
bool QueueEmpty(Queue* pq);
//取队头元素
QDatatype QueueFront(Queue* pq);
//取队尾元素
QDatatype QueueBack(Queue* pq);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.2 "队列"的常见接口:
  • 二、接口的具体实现:
    • 2.1 "队列"的"初始化"操作(QueueInit)
      • 2.2 "入队"操作(QueuePush)
        • 2.3 "队列"判空(QueueEmpty)
          • 2.4 “出队”(QueuePop)
            • 2.5 "队列"长度函数
              • 2.6 取"队头"和"队尾"元素
                • 2.7 "队列"的销毁:
                • 三、结语:
                • 四、总代码:
                  • 4.1 主测试区(test.c)
                    • 4.2 接口实现区(Queue.c):
                      • 4.3 接口声明区(Queue.h):
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档