n3.队列

本文详细介绍了队列的基本概念、顺序存储方式(包括数组实现和环形数组)以及链式存储方式,探讨了队列的入队和出队操作,并提到了易错点,如圆盘状循环队列的使用。
摘要由CSDN通过智能技术生成

1.队列

  • 和堆栈一样,队列也属于受限制的线性表。
    在这里插入图片描述

和堆栈不同的是,堆栈只能在一端进行出栈和入栈 (先进后出),而队列只能在尾部插入,在头部删除(先进先出)**。
在这里插入图片描述

队列的操作

——入看满不满,出看空不空——
在这里插入图片描述

2.队列的顺序储存

  • 队列的顺序储存一般由一个一维数组+记录头部位置的变量front+记录尾部位置的变量rear组成。
    对比堆栈,只需要数组和指示栈顶位置的变量Top。

  • front等于第一个元素的前一个下标索引;rear等于最后一个元素的下标索引,且一开始空队列front和rear的值都为-1。

  • 数据按照先来后到的原则从头往后排、先入先出,插入元素在尾部插入,与rear相关;删除元素在头部删除,与front相关。
    在这里插入图片描述

  • 当列表的最后方已经没有空间,但是前方还有余下的空间的时候,如何再插入元素呢:
    在这里插入图片描述

  • 顺环队列:
    在这里插入图片描述

当顺环队列加满的时候,再一次 front == rear 。
解决方法:
1使用额外标记Size或者Tag。Size用来记录数组的大小,Size=0就为空,Size=n就满了;插入一个元素,Tag=1、删除一个元素Tag=0,那么可以根据Tag的值来看当front==rear的时候究竟是空还是满。
2大小为n的数组a[n],可以放入n个元素,但是仅使用n-1个空间,那么就不会出现满的情况。注意不是不可使用头部所空的空间,而是无论是用什么空间,只要保证元素个数不超过n-1即可!
以下代码基于方法2;

初始化

#define MaxSize <最大个数>
struct QNode{
	ElementType Data[MaxSize];
	int rear;
	int front;
};
typedef struct QNode* Queue;

入队列

void AddQ(Queue PtrQ,ElementType item)
{// (PtrQ->rear+1)%MaxSize 实现索引下标的循环
	if( (PtrQ->rear+1)%MaxSize == PtrQ->front )
		printf("队列已满,不可插入");//检查队列是不是满了
	else
	{
		PtrQ->rear = (PtrQ->rear+1)%MaxSize;
		PtrQ->Data[PtrQ->rear] = item;
	}
}
比如一个数组a[n = 3],它的元素下标分别为a[0],a[1],a[2]。当rear指向a[2],并且a[0]和a[1]都是空的,要插入一个元素到a[0],(2+1) % 3 = 0!

出队列

删除队列头部的元素,并且返回这个歌元素的值

ElementType DeleteQ(Queue PtrQ)
{
	if(PtrQ->front == PtrQ->rear)
		printf("队列是空的,无法出队");
	else
	{	
		PtrQ->front = (PtrQ->front+1) % MaxSize;//front+1正好就是原来头部元素的位置
		result = PtrQ->Data[PtrQ->front];//在这里正好返回
	}
	return result ;
}

3.队列的链式储存

可以用一个单链表来实现,插入和删除操作在链表的两头进行。

  • 链表的Head端对于插入和删除操作都是可以是实现的:插入操作,新节点指向Head指向的结点,Head指向的结点改为指向新节点。删除操作,Head直接跳过第一个节点指向第二个节点。
  • 链表的尾端:插入操作,最后一个节点指向新节点。非常不方便进行删除操作,因为这是单向链表,删除最后一个节点之后无法得知上一个节点在哪。
    所以只能让链表的Head端做front删除,尾端做rear插入
    理解:队列是一种先进先出(FIFO)的数据结构,应该保持元素的顺序,第一个结点先产生,记为front;最后那个节点记为rear。

初始化

//建立链表的 结点结构
struct Node{
	ElementType Data;//每个节点包含的数据
	struct Node* Next;//每个节点和后一个节点进行连接
};
//链表队列信息 储存结构--代表队列
struct QNode{
	struct Node* rear;//指向链表中作为队列尾的结点
	struct Node* front;//指向链表中作为队列头的结点
};
typedef struct QNode* Queue;
Queue PtrQ;

注意,不需要头结点!!
在这里插入图片描述

出队

删除头结点(第一个节点),然后返回它的Data值; 出队通常先检查空不空,排除链表为空的情况之后要马上跟上---释放结点的copy、以及return的赋值--,在链表出队程序的--最后再释放空间、return值--。因为如果在if语句块中再进行则代码需要重复多次。

ElementType DeleteQ(Queue PtrQ)
{
	if(PtrQ->front == NULL)//第一步总是要判断是不是空的
		printf("这个链表是空的");
		return NULL;//队列为空,要执行中断操作
	struct Node* Front = PtrQ->front;//保存一下便于后边释放内存
	ElementType copy = Front->Data;
	if(PtrQ->front == PtrQ->rear)
		PtrQ->front = PtrQ->rear = NULL;//考虑这个链表只有一个节点,删除之后front和rear所指的都是NULL,否则的话只要改变front就行了
		PtrQ->front = PtrQ->rear = NULL;  */
	else{
		PtrQ->front = Front->Next;
	}
	free(Front);//释放掉删除的节点的内存
	return copy;//返回出队节点的值
}

入队

void AddQ(Queue PtrQ,ElementType item)
{
	struct Node* newNode = malloc(sizeof(struct Node));
	  if (newNode == NULL) { // 检查内存分配是否成功
        printf("内存分配失败");
        return ;
    }
	newNode->Data = item;
	newNode->Next = NULL;
	if(PtrQ->front == NULL)//如果队列为空,front和rear指向的都是NULL
	{
		PtrQ->front = PtrQ->rear = newNode;//第一个是new最后一个还是new
	}
	else//至少有一个结点的情况
	{//front指向第一个节点不动,rear指向的末结点先指向new,然后再让rear指向new,完成更新
		PtrQ->rear->Next = newNode;//将新节点连接到队尾
		PtrQ->rear = newNode;//更新rear指针
	}
}

易错题:
在这里插入图片描述

提示:先插7个,后删3个(圆盘状循环队列)

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值