数据结构-----对列

前言

Hello, 小伙伴们,你们的作者菌又来了,前不久,我们学习了一种数据结构----栈,他特殊的性质使得他在一些数据管理的问题上被广泛的使用,那今天,我们就来学习另一种十分重要的数据结构--对列。

在开始之间,还是按例求三,如果你喜欢我的内容,就请不要忘记,点赞、评论和收藏,你们的支持就是我更新的动力,万分感谢!!

好,我们先在开始。

1.队列的介绍

基本概念:

只允许在⼀端进⾏插⼊数据操作,在另⼀端进⾏删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)

入队列:进行插入操作的一段为队尾;

出队列:进行删除操作的一端称为对头。

队列的底层结构选型:

队列也可以用数组和链表的方式链实现,使用链表的结构实现会更加的优秀,因为如果使用数组的结构,出队列在数组的头部进行,效率会十分底下!! 

2.队列的实现

我门还是先创建三个文件(就向实现其他数据结构一样):

 2.1队列结构的定义:

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

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

怎样来理解这样的定义呢?

队列的定义底层使用的确实是单链表的结构,但是特殊的就是,他只能在头部出数据,只能在为部插入数据,所以,我们可以使用两个结构体,来实现队列:

phead用于出数据;

ptail用于输入数据。

 2.2队列的初始化(QueueIit函数的实现)

2.2.1函数的定义

//初始化队列
void QueueInit(Queue* ps);

2.2.2函数的实现

//初始化队列
void QueueInit(Queue* ps)
{
	assert(ps);
	ps->phead = ps->ptail = NULL;
}

初始化的操作与单链表相似。

代码测试:

2.3队列的数据插入(QueuePush函数的实现)

2.3.1 函数的定义

//入队列
void QueuePush(Queue* ps, QDataType  x);

这个也和单链表的结构相似,但是要注意几点,我们先来看函数的是实现代码:

2.3.2函数的实现


QueueNode* BuyNode(QDataType x)
{
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc Fail!!");
		exit(1);
	}
	newnode->x = x;
	newnode->next = NULL;
	return newnode;
}
//队列的销毁

void QueuePush(Queue* ps, QDataType  x)
{
	assert(ps);
	QueueNode* New = BuyNode(x);
	if (ps->phead == NULL)
	{
		ps->phead = ps->ptail = New;
	}
	else
	{
		ps->ptail->next = New;
		ps->ptail = ps->ptail->next;
	}
}

1.我们注意不要将QueueNode 和Queue的结构混淆;

2.一定要记得,将新节点的next指针置位NULL;

3.要考虑到ps->phead 和 ps->ptail都为NULL的情况!!

代码测试:

 

入队列的操作就完成了!! 

2.4队列的出数据 (QueuePop函数的实现)

2.4.1函数的定义:

//出队列
void QueuePop(Queue* ps);

2.4.2代码的实现

这里的出队列,其实和单链表的头删是一个逻辑,还是要考虑到一下几点:

1.删除数据的前提是,队列中有元素可删!

2.不能将队列删除为NULL后,任然删除数据!!

bool IsEmpty(Queue* ps)
{
	return ps->phead == NULL;
}
//IsEmpty函数可以判断队列存储数据的情况
void QueuePop(Queue* ps)
{
	assert(ps);
	assert(!IsEmpty(ps));
	QueueNode* ret = ps->phead->next;
	free(ps->phead);
	ps->phead = ret;
}

 代码测试:

2.5取队列的头(尾)数据(QueueTop 函数和 QueueBack函数的实现)

2.5.1函数的定义

//取对头数据
QDataType QueueTop(Queue* ps);
//取队尾数据
QDataType QueueBack(Queue* ps);

这样的操作十分的简单,就和前面我们学习栈的时候,取数据的操作大致相同

2.5.2函数的实现

//取对头数据
QDataType QueueTop(Queue* ps)
{
	assert(ps && !IsEmpty(ps));
	return ps->phead->x;
}
//取队尾数据
QDataType QueueBack(Queue* ps)
{
	assert(ps && !IsEmpty(ps));
	return ps->ptail->x;
}

 这样的操作十分的简单,我们只需要确保队列中有元素,就可以取出队头和对尾元素。

接下来我们来测试一下,看看能不能达到我们想要的效果:

2.6队列中的数据个数 

在这里,我们可以先写一个函数CountSize来解决这样的问题:

//得出队列中的数据元素个数
int CountSize(Queue* ps);
int CountSize(Queue* ps)
{
	assert(ps);
	QueueNode* pcur = ps->phead;
	int size = 0;
	while (pcur)
	{
		size++;
		pcur = pcur->next;
	}
	return size;
}

经过测试,我们可知,这样是可以解决问题的,但是这样做是绝对不规范的!! 

因为队列和栈一样,不能被遍历,也不能被随机的访问!!

同时,如果外界的用户要进行频繁的数据个数获取,我们出于时间复杂度的考虑,因该怎样来修改我们的代码呢? 

所以,我们要怎样才能解决问题呢?

或许,我们在定义队列的节点时,就加上一个元素,来记录我们插入数据的个数

如,这是我们原来的队列定义:

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

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

我们可以修改为

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

typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
    int size;//增加一个元素来记录存储数据的个数!!
}Queue;

每插入一次数据,我们就然size++;

每出一次队列,size--;

在要获取元素个数时,我们只需要,将size返回就行!所以,我们可以来试试这样的方法:

所以CountSize我们可以改写为 

int CountSize(Queue* ps)
{
	assert(ps);
	return ps->size;
}

接下来,我们来测试一下:

 

 2.7队列的销毁(QueueDstroy函数的实现)

 2.7.1函数的定义:

void QueueDstroy(Queue* ps);
//队列的销毁

2.7.2函数的实现 

void QueueDestroy(Queue* ps)
{
	assert(ps && !IsEmpty(ps));
	QueueNode* ret = ps->phead;
	while (ret)
	{
		QueueNode* next = ret->next;
		free(ret);
		ret = next;
	}
	ps->ptail = ps->phead = NULL;
	ps->size = 0;
}

销毁的操作和之前链表的操作相似,如果对链表的知识掌握的够好,我们可以直接仿写!!

3.代码展示:

3.1Queu.h

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

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

typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
	int size;

}Queue;

//初始化队列
void QueueInit(Queue* ps);
//队列的销毁
void QueueDestroy(Queue* ps);
//入队列
void QueuePush(Queue* ps, QDataType  x);
//出队列
void QueuePop(Queue* ps);

//取对头数据
QDataType QueueTop(Queue* ps);
//取队尾数据
QDataType QueueBack(Queue* ps);


//得出队列中的数据元素个数
int CountSize(Queue* ps);
bool IsEmpty(Queue* ps);

3.2Queue.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"Queue.h"

//初始化队列
void QueueInit(Queue* ps)
{
	assert(ps);
	ps->phead = ps->ptail = NULL;
	ps->size = 0;
}
void QueueDestroy(Queue* ps)
{
	assert(ps && !IsEmpty(ps));
	QueueNode* ret = ps->phead;
	while (ret)
	{
		QueueNode* next = ret->next;
		free(ret);
		ret = next;
	}
	ps->ptail = ps->phead = NULL;
	ps->size = 0;
}

QueueNode* BuyNode(QDataType x)
{
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc Fail!!");
		exit(1);
	}
	newnode->x = x;
	newnode->next = NULL;
	return newnode;
}

void QueuePush(Queue* ps, QDataType  x)
{
	assert(ps);
	QueueNode* New = BuyNode(x);
	if (ps->phead == NULL)
	{
		ps->phead = ps->ptail = New;
	}
	else
	{
		ps->ptail->next = New;
		ps->ptail = New;
	}
	ps->size++;
}
bool IsEmpty(Queue* ps)
{
	return ps->phead == NULL;
}
void QueuePop(Queue* ps)
{
	assert(ps);
	assert(!IsEmpty(ps));
	QueueNode* ret = ps->phead->next;
	free(ps->phead);
	ps->phead = ret;
	ps->size--;
}
//取对头数据
QDataType QueueTop(Queue* ps)
{
	assert(ps && !IsEmpty(ps));
	return ps->phead->x;
}
//取队尾数据
QDataType QueueBack(Queue* ps)
{
	assert(ps && !IsEmpty(ps));
	return ps->ptail->x;
}
//得出队列中的数据元素个数
int CountSize(Queue* ps)
{
	assert(ps);
	return ps->size;
}

3.3test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
void Test()
{
	Queue  s;
	QueueInit(&s);
	QueuePush(&s, 0);
	QueuePush(&s, 1);
	QueuePush(&s, 2);
	QueuePop(&s);
	//取对头数据
	printf("Top:%d\n", QueueTop(&s));
	//取队尾数据
	printf("Back:%d\n", QueueBack(&s));
	printf("Size:%d\n", CountSize(&s));
	QueueDestroy(&s);
	printf("Size:%d\n", CountSize(&s));
}

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

好,今天的学习就到这里,我们下期再见,拜拜!!!

  • 33
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 37
    评论
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值