IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 新手向C语言实现特殊数据结构——队列 -> 正文阅读

[数据结构与算法]新手向C语言实现特殊数据结构——队列

前言

使用单向无头不循环链表实现队列。

队列:符合先进先出逻辑的特殊数据结构。

不适合用数组来实现,虽然入队便捷但是出队时需要挪动队首后的所有元素,效率略低。

单向不循环链表对于找尾的效率确实低,但是可以在结构体中定义出队首节点和队尾节点,分别管理使得入队和出队的效率都高。所以就需要定义两个结构体,一个管理节点的内容,一个管理整个队列。

建议先跳转到第三部分阅读结构体定义的代码,以便后续便于理解。

关于改变链表头节点的方式:

1、二级指针(传指针解引用改变)

2、返回新头(接受改变值)

3、带哨兵位的头节点(本质上不会改变头节点)

4、结构体包一起(大结构体一级指针改变)

此次选择第四种方式。

可能这时候就会有同学这样问了:为什么在实现单向不循环链表的时候不把结构体包一起呢?这样不就解决了找尾效率低的问题吗?

哎,这位同学就年轻了啊。你这样解决了尾插的问题,但是能解决尾删的问题吗?单向不循环链表中时不能通过一个节点找到上一个节点的。也就是尾删了后还是要找尾···

一、易错接口详解

1.1 出队

出队算法:法一:保存下一个节点为next,再删除。

法二:保存要删除的节点为del,把头结点赋值为新节点,然后free掉del

此次选择法一。

需要注意队列为空时调用此接口会出现非法访问的错误,所以需要提前断言报错。

这里把判断是否为空的功能封装成一个函数,详情请跳转至第二部分查看。

特殊情况:当链表删除掉最后一个节点时,ptail会成为野指针。

所以仅有一个节点时就直接free掉,再将头指针和尾指针都赋值为NULL

正常情况下,出队时记得保留队头节点的下一节点的地址,以便头节点迭代。

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
}

1.2 入队

入队算法:为新的头节点开辟新空间,并插入有效数据。之后的步骤相当于链表的尾插。

但是需要注意特殊情况:队列中没有节点时需要直接把头尾节点都改为新节点。

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	//新节点初始化结束
	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
}

二、 简单接口的实现

2.1 队列的初始化

算法:将头指针和尾指针都赋值为NULL

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

2.2 队列节点计数

int QueueSize(Queue* pq)
{
	assert(pq);
	int count = 0;
	QueueNode* cur = pq->phead;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

关于链表计数的接口,如果调用频繁的话就可以在大结构体Queue中加入一个计数成员,入队或出队时修改。如果调用不频繁,就直接在接口中进行计算。

2.3 队列的销毁

算法:利用创建的新指针cur从头走到尾,走到一个节点就删除一个节点,在删除前还需要保留cur指针的下一个节点地址,以便cur指针迭代。最后还不要忘了将头节点的指针phead和为节点的指针ptail指向NULL

void QueueDestory(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->phead;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
}

2.4 判断队列是否为空

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
}

2.5 返回队头数据

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

2.6 返回队尾数据

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

三、头文件引用、函数与结构体定义

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

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

typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
}Queue;

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

四、拾枝杂谈——队列接口调用方式

首先创建一个大结构体Queue的对象q,再把对象初始化,再入队,打印的时候必须打印一个队首元素就将队首元素进行出队,直至队列为NULL时即可将队中所有元素打印完成,最终销毁整个队列,避免内存泄漏。

void Test2()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	QueueDestory(&q);
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-07 14:04:31  更:2021-10-07 14:04:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 13:21:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码