C语言 队列的实现全解析

目录
  • 队列的实现
    • 基本概念
    • 创建结构体
    • 初始化结构体
    • 销毁队列结构体
    • 入队
    • 出队
    • 判断队列是否为空
    • 访问对头的值
    • 访问队尾的值
    • 返回队列的长度
    • Queue.h
    • Queue.c
    • Test.c

“ 江天一色无纤尘,皎皎空中孤月轮。 ”

队列的实现

基本概念

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

FIFO(First In First Out)

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

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低需要挪动数据O(N)。而链表结构头删只需要O(1)。尾插定义一个尾指针,也只需要O(1)。

创建结构体

这是一个嵌套结构体。

实参q的地址传给了形参pq。pq就是一个指向结构体Queue的指针。Queue里面的head是指向队列对头的指针,tail是指向队尾的指针。

int main()
{
//创建结构体变量q
//需要传q的地址过去。
	Queue q;

	return 0;
}

定义一个尾指针tail方便入队的尾插。头指针head方便出队时的头删。

typedef int QDataType;
//节点结构体
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;
//头指针和尾指针的结构体
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;

初始化结构体

才开始还没有创建队列的空间,所以只需要初始化第一个结构体就ok了。队列初始状态需要对头和队尾指向同一位置,且都是空。

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}

销毁队列结构体

这次我把销毁结构体放在初始化结构体的后面,原因是内存泄漏很严重,但是经常会忘记销毁结构体。创建意味着就要销毁,二者对立,所以排在初始化的后面,理所应当。

void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

入队

入队的时候,会创建新的节点。最好最好把新开的newnode节点初始化。把他的next置为空,方便后期求队列长度函数,和出队函数的循环条件的书写。

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);
	//下面两个初始化很有必要
	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

出队

因为Queue结构体不可能为空,所以需要断言

还需要断言pq->head和tail都不为空。

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

判断队列是否为空

为空返回true,为假返回false

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

访问对头的值

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

返回队列的长度

长度不可能为负数,所以返回类型为size_t

size_t QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}

	return size;
}

Queue.h

#pragma once

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

typedef int QDataType;

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

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

	//size_t size;
}Queue;

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

Queue.c

#include "Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}

void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

size_t QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}

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

Test.c

void TestQueue()
{
	Queue q;
	QueueInit(&q);

	QueuePush(&q, 1);
	QueuePush(&q, 2);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);

	QueuePush(&q, 3);
	QueuePush(&q, 4);

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

int main()
{

	TestQueue();

	return 0;
}

到此这篇关于C语言 队列的实现全解析的文章就介绍到这了,更多相关C语言 队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言实现链队列代码

    本文实例为大家分享了C语言实现链队列的具体代码,供大家参考,具体内容如下 #include <stdio.h> /* 队列的结构体 */ typedef int DataType; #define NODE_LEN sizeof(NODE) /* 队列的节点 */ typedef struct stNode { DataType data; struct stNode* next; }NODE; /* 队列 */ typedef struct stQueue { NODE* head; //队

  • C语言实现链队列基本操作

    队列的链式存储结构实现,相比于循环队列实现要复杂一些,但是没有队满的限制. 头文件声明 #include <stdio.h> #include <stdlib.h> /** * 队列的链式存储实现 * [带头结点的单链表] * [-类似于链栈,队列的链式存储实现也不会出现队满的情况] */ //数据类型 typedef int ElemType; //定义节点 typedef struct SqQueueNode { ElemType data;//数据域 struct SqQue

  • C语言版实现链队列

    本文实例为大家分享了C语言实现链队列的具体代码,供大家参考,具体内容如下 源文件部分:  指针没学好的同学很难看懂^_^,有点乱,希望对大家有点帮助. #include<stdio.h> #include<malloc.h> #include<stdlib.h> #include<string.h> typedef int Elemtype; #include"LQueue.h" int main() { Deque head; inst

  • C语言数据结构进阶之栈和队列的实现

    目录 栈的实现: 一.栈的概念和性质 二.栈的实现思路 三.栈的相关变量内存布局图 四.栈的初始化和销毁 五.栈的接口实现: 1.入栈 2.出栈 3.获取栈顶的数据 4.获取栈的元素个数 5.判断栈是否为空 队列的实现: 一.队列的概念和性质 二.队列的实现思路 三.队列相关变量的内存布局图 四.队列的初始化和销毁 五.队列的接口实现: 1. 入数据 2.出数据 3.取队头数据 4.取队尾数据 5.获取队列元素个数 6.判断队列是否为空 总结 栈的实现: 一.栈的概念和性质 栈(stack)又名

  • C语言循环队列与用队列实现栈问题解析

    目录 “莫听穿林打叶声,何妨吟啸且徐行” 这里是目录 循环队列题目描述题目链接思路分析代码实现 用队列实现栈题目描述题目链接思路分析代码实现 循环队列 循环队列: 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环循环队列的好处:可以重新利用队列的空间.我们可以利用这个队列之前用过的空间.在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间.但是使用循环队列,我们能使用这些空间去存储新的值. 题目描述 设计你

  • C语言实现循环队列

    本文实例为大家分享了C语言实现循环队列的具体代码,供大家参考,具体内容如下 注意事项: 1.循环队列,是队列的顺序表示和实现.因为是尾进头出,所以和顺序栈不同的是需要将顺序队列臆造成一个环状的空间,以便在尾部添加满之后从头部空位开始插入. 2.也可以使用数组队列,也就是不能动态增长的顺序队列,这样不需要每次取模最大值来构成环形空间.每次插入新的队列尾元素时,尾指针增1,每当删除队列头元素时,头指针增1. 3.尾指针会出现在头指针之前,由此特性,循环队列在无法预估使用大小时,不宜使用. 4.在每一

  • C语言实现循环队列基本操作

    循环队列依靠取模运算,实现队列中数据元素的逻辑成环操作.其相比队列的顺序存储实现,可以避免"假溢出"的问题. 头文件声明 #include <stdio.h> #include <stdlib.h> /* * 循环队列实现 */ //数据元素上限 #define MaxSize 50 //定义数据类型 typedef int ElemType; /*结构体定义*/ typedef struct SqQueue { ElemType data[MaxSize];/

  • C语言实现链队列

    记录一下C语言实现的链队列代码,供大家参考,具体内容如下 #include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int ElemType; //链队列的结点定义 typedef struct node{ ElemType val; struct node* next; }QueueNode; //链队列的定义,包含队头指针和队尾指针 typedef struct queue { QueueNod

  • C语言超详细讲解栈与队列实现实例

    目录 1.思考-1 2.栈基本操作的实现 2.1 初始化栈 2.2 入栈 2.3 出栈 2.4 获取栈顶数据 2.5 获取栈中有效元素个数 2.6 判断栈是否为空 2.7 销毁栈 3.测试 3.1测试 3.2测试结果 4.思考-2 5.队列的基本操作实现 5.1 初始化队列 5.2 队尾入队列 5.3 队头出队列 5.4 队列中有效元素的个数 5.5 判断队列是否为空 5.6 获取队头数据 5.7 获取队尾的数据 5.8 销毁队列 6.测试 6.1测试 6.2 测试结果 1.思考-1 为什么栈用

  • C语言 队列的实现全解析

    目录 队列的实现 基本概念 创建结构体 初始化结构体 销毁队列结构体 入队 出队 判断队列是否为空 访问对头的值 访问队尾的值 返回队列的长度 Queue.h Queue.c Test.c “ 江天一色无纤尘,皎皎空中孤月轮. ” 队列的实现 基本概念 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 队列也可以数组和链表的结构实现,

  • C语言 队列的实现全解析

    目录 队列的实现 基本概念 创建结构体 初始化结构体 销毁队列结构体 入队 出队 判断队列是否为空 访问对头的值 访问队尾的值 返回队列的长度 Queue.h Queue.c Test.c 队列的实现 基本概念 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数

  • C语言实现五子棋功能全解析

    目录 1.game.h 2.test.c 3.game.c 4.游戏功能详解 (1).棋盘初始化 (2).棋盘的打印 (3).玩家下棋 (4).电脑下棋 (5).判断游戏输赢 (6).判断棋盘是否满了 5.AI算法下棋 (1).判断自己是否会赢(CheckComputer) (2).对玩家进行拦截(CheckPlayer) (3).加入AI算法后game.c的改动 1.game.h game.h:自定义头文件,用于: 库函数头文件的包含 符号与结构的声明 函数的定义 //防止头文件被重复包含 #

  • C语言自定义类型全解析

    目录 前言 结构体类型 结构体的声明 结构体变量的定义与初始化 结构体的自引用 结构体的访问 结构体的传参 传结构体 传地址 结构体的内存对齐(强烈建议观看) 位段 位段的声明 位段的内存管理 位段的跨平台性  枚举类型 枚举类型的定义 枚举类型赋予初始值 枚举类型的优点 联合体类型 联合体的定义 联合体的特点  联合体内存大小的计算 前言 初学C语言 我们先接触的都是内置的类型 比如说int char short float double long等等 这一期就来聊一聊自定义类型的知识 结构体

  • webpack3之loader全解析

    首先亮出webpack官方网站,webpack能干什么?官网给出的答案就是,一句话,让一切变得简单! 各式各样的loader层出不穷,让我们在构建时不知所措,于此,总结下loader的全解析. 概念 loader,顾名思义,加载器,英文的解释如下: Loaders are transformations that are applied on the source code of a module. They allow you to pre-process files as you impor

  • shell脚本语言的使用(超全超详细)

    1.shell的概述 shell 是一种脚本语言 脚本:本质是一个文件,文件里面存放的是 特定格式的指令,系统可以使用脚本解析器 翻译或解析 指令 并执行(它不需要编译) shell 既是应用程序 又是一种脚本语言(应用程序 解析 脚本语言) shell命令解析器: 系统提供 shell命令解析器: sh ash bash 查看自己linux系统的默认解析:echo $SHELL shell脚本是一种脚本语言,我们只需使用任意文本编辑器,按照语法编写相应程序,增加可执行权限,即可在安装shell

  • java agent使用全解析

    今天打算写一下 Java agent,一开始我对它的概念也比较陌生,后来在别人口中听到 字节码插桩,bTrace,Arthas后面才逐渐了解到Java还提供了这么个工具. JVM启动前静态Instrument Java agent 是什么? Java agent是java命令的一个参数.参数 javaagent 可以用于指定一个 jar 包,并且对该 java 包有2个要求: 这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项. Premain-Class

  • C# 单元测试全解析

    目录 1.前言 2.单元测试 2.1 单元测试的定义 2.2 单元测试的好处 2.3 单元测试的原则 3..NET 中的测试框架 3.1 MS Test 3.2 NUnit 3.3 XUnit 4.XUnit 的基本使用 5.其他 1.前言 "不会写单元测试的程序员不是合格的程序员,不写单元测试的程序员不是优秀的工程师." 那么问题来了,什么是单元测试,如何做单元测试. 2.单元测试 2.1 单元测试的定义 按照维基百科上的说法,单元测试(Unit Testing)又称为模块测试, 是

  • C语言队列和应用详情

    目录 1.队列的原理 2.队列的作用 3.队列程序设计思路 4.入列 5.出列 6.掌握队列程序编写 7.队列的应用 1.队列的原理 队列原理其实就像一个管道,如果我们不断往管道里面塞乒乓球,每个乒乓球在管道里就会排列一条队形.先进去的乒乓球就会先出来,这个就是队列的先进先出的规则. 球从左边进去,进去的动作就是入列,然后进去的球在管道里排成一个队列,这个叫队列缓存,说白了就是数组,那么这里存了5个球就相当于是buff[5];这样的意思,最右边出来的1号球就是最早进去的球,出来的这个动作叫出列,

  • Java Mybatis框架由浅入深全解析下篇

    目录 前言 什么是Maven Maven环境配置 Maven 构建生命周期 Maven项目的创建 目录结构 pom.xml文件 什么是pom.xml文件 加入项目所需依赖 添加资源文件的指定 总结 前言 上一篇我们第一次测试了Mybatis框架,并且成功了. 本想直接推进学习框架配置,但是很多小伙伴对Maven不了解,今天就来浅谈一下Maven. 今天我们就来剖析pom.xml配置文件,这个pom.xml文件,是我们构建maven项目的配置文件,既然我们使用到了,就利用本篇文章学习一下吧.这里只

随机推荐