数据结构:Queue队列

一、队列的概念

1、队列的定义

队列:数据结构线性表的一种,它与栈不同,栈是先进后出,而队列是先进先出,在队尾入列,在队头出列。

队头(head):队列中出队列的一端

队尾(tail):队列中插入队列的一端
在这里插入图片描述

二、队列的顺序储存结构

1.顺序存储的理解

在内存上开辟一段连续的内存空间
在这里插入图片描述

​将低地址空间作为队头,向高地址存放数据
因此我们定义一个队列结构

#define Queue_Max 6
typedef int QueueType;
typedef struct QueueNode
{
    QueueType list[Queue_Max];//队列数组,容量为5
    int first;//首元素前一个位置下标
    int rear;//尾元素下标位置
}Queue;

在这里插入图片描述

当队列为空时,此时队列没有元素,令first=rear=-1,当存放一个数据x时,令rear+=1,list[rear]=x,此时rear指向的是尾元素下标,first不变,以此类推,当存放6个数据后,rear变为了5,此时队列满了,以及无法再插入数据。
在这里插入图片描述

当队列满时,我们进行出队列,当出一个元素时,令first+=1,然后取出该下标的数据,以此类推,当出队列至最后一个数据时,first=4,出完后,first=rear=5,此时队列为空,且无法再存储数据。
在这里插入图片描述

综上,我们可知
1.队列为空的条件是first==rear
2.队列为满的条件是rear=Queue_Max-1
3.进队列时,先将rear下标+1,再插入数据至list数组的rear位置
4.出队列时,先将first下标+1,再取出list数组的first位置的数据

2.顺序存储的算法实现

2.1初始化队列

//初始化
void QueueInit(Queue* que)
{
	assert(que);//断言是否为空
	que=(Queue*)malloc(sizeof(Queue));
	que->first=que->rear=-1;//
}

2.2销毁队列

void QueueDestroy(Queue* que)
{
	free(que);
}

2.3进队列

void QueuePush(Queue* que, QueueType x)
{
	assert(que);
	if(!QueueFull(que)//检查队列是否满了
	{
	    rear+=1;
	    que->list[rear]=x;
	}
}

2.4出队列

void QueuePop(Queue* que,QueueType* e)
{
	assert(que);
	if(!QueueEmpaty(que)//判断队列是否为空
	{
	    first+=1;
	    *e=que->list[first];
	}
}

2.5判断队列是否为满

bool QueueFull(Queue* que)
{
    assert(que);
    return que->rear==Queue_Max-1;
}

2.6判断队列是否为空

bool QueueEmpaty(Queue* que)
{
    assert(que);
    return que->first==que->rear;
}

2.7取队尾元素

QueueType QueueBack(Queue* que)
{
	assert(que);
	assert(!QueueEmpty(que));
	return que->list[rear];
}

3、循环队列

在顺序储存结构基础上实现循环队列,就是可以实现出队列的空间也可以插入数据,形成循环。
比如当队列为空且rear=Queue_Max-1时,如果是循环队列,那么rear会变成0,然后在list数组的rear位置插入数据
在这里插入图片描述

在这里插入图片描述

当我们再插入5个数据时,此时rear=first且队满,但是和判断队空的条件重复了,那么怎么办才能将两种情况区分开呢?
如果我们让rear和first初始化为0,使first指向的数组下标位置始终为空(数组不能free,实际含有数据,所以我们只需将list数组的first位置看作是无效数据),当插入4个数据后此时队满,满足rear=(first-1+Queue_Max)%Queue_Max,这样就能把空和满区分开来。
在这里插入图片描述

因此我们需要将原来的代码改进

//改进后
//初始化
void QueueInit(Queue* que)
{
    que=(Queue*)malloc(sizeof(Queue));
    que->first=que->rear=0;
}
//判断队满
bool QueueFull(Queue* que)
{
    assert(que);
    return rear==(first-1+Queue_Max)%Queue_Max;
}
//进队
void QueuePush(Queue* que,QueueType x)
{
    assert(que);
    assert(!QueueFull(que));
    rear=(rear+1)%Queue_Max;
    que->list[rear]=x;
}
//出队
void QueuePop(Queue* que,QueueType* e)
{
    assert(que);
    assert(!QueueEmpaty(que));
    first=(first+1)%Queue_Max;
    *e=que->list[first];
}

三、队列的链式储存结构

1、链式储存的理解

队列的数据之前的逻辑关系是线性结构,因此可以用链式的形式来储存,这种链式储存的形式叫做链队。这里我们使用单链表的形式,所以只能在链表的表头进行删除操作(出队),在链表的表尾进行插入操作(进队),因此我们需要记录链表的头结点(head)和尾结点(tail),和链栈一样,链队也不存在队满上溢出的情况。

2、队列链式结构的常见操作

//初始化
void QueueInit(Que* que);
//销毁
void QueueDestroy(Que* que);
//插入
void QueuePush(Que* que, QueDateType x);
//删
void QueuePop(Que* que);
//判断空
bool QueueEmpty(Que* que);
//打印
void QueuePrint(Que* que);
//创建队列元素
Queue* QueueBuy(QueDateType x);
//取队列首元素
QueDateType QueueFront(Que* que);
//取队列尾元素
QueDateType QueueBack(Que* que);

3、算法实现

//初始化
void QueueInit(Que* que)
{
	assert(que);
	que->head = que->tail = NULL;
}
//创建队列元素
Queue* QueueBuy(QueDateType x)
{
	Queue* newnode = (Queue*)malloc(sizeof(Queue));
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
//销毁
void QueueDestroy(Que* que)
{
	assert(que);
	if (que->head == que->tail)
	{
		free(que->head);
		que->head = que->tail = NULL;
	}
	else
	{
		Queue* cur = que->head;
		while (cur)
		{
			Queue* next = cur->next;
			free(cur);
			cur = next;
		}
	}
}
//插入
void QueuePush(Que* que, QueDateType x)
{
	assert(que);
	Queue* newnode = QueueBuy(x);
	if (que->head == NULL)
	{
		que->head = newnode;
		que->tail = newnode;
	}
	else
	{
		que->tail->next = newnode;
		que->tail = newnode;
	}
}
//删
void QueuePop(Que* que)
{
	assert(que);
	assert(que->head);
	if (que->head == que->tail)
	{
		free(que->head);
		que->head = que->tail = NULL;
	}
	else
	{
		Queue* next = que->head->next;
		free(que->head);
		que->head = next;
	}
}
//判断空
bool QueueEmpty(Que* que)
{
	assert(que);
	return que->head == NULL;
}
//打印
void QueuePrint(Que* que)
{
	assert(que);
	printf("pop<- ");
	Queue* cur = que->head;
	while (cur)
	{
		Queue* next = cur->next;
		printf("%d ", cur->data);
		cur = next;
	}
	printf(" <-push\n\n");
}

//取队列首元素
QueDateType QueueFront(Que* que)
{
	assert(que);
	assert(!QueueEmpty(que));
	return que->head->data;
}
//取队列尾元素
QueDateType QueueBack(Que* que)
{
	assert(que);
	assert(!QueueEmpty(que));
	return que->tail->data;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值