数据结构基础讲解(五)——队列专项练习

本文数据结构讲解参考书目:

通过网盘分享的文件:数据结构  C语言版.pdf
链接: https://pan.baidu.com/s/159y_QTbXqpMhNCNP_Fls9g?pwd=ze8e 提取码: ze8e

数据结构基础讲解(四)——栈专项练习-CSDN博客

个人主页:樱娆π-CSDN博客


队列的表示和操作的实现

队列的类型定义

ADT Queue {数据对象:D={ai l ai 含于ElemSet ,i=1,2,…, n ,n>=0}

数据关系:R={ <i-1,ai>  | ai-1,ai含于D ,i=2, …, n}

约定其中a1端为队列头,an端为队列尾。

基本操作:

}

基础操作

基本操作初始条件操作结果
InitQueue (&Q)/构造一个空队列Q
Des t royQueue (&Q)构造一个空队列Q队列Q被销毁, 不再存在
ClearQueue (&Q)队列Q已存在将Q清为空队列
QueueEmpty (Q)队列Q已存在若Q为空队列,则返回true, 否则返回false
QueueLength(Q)队列Q已存在返回Q的元素个数,即队列的长度
GetHead(Q}Q为非空队列返回Q的队头元素
EnQueue (&Q, e}队列Q已存在插入元素e为Q的新的队尾元素
DeQueue(&Q, &e)Q为非空队列删除Q的队头元素,并用e 返回其值从队头到队尾,依次对Q的每个数据元素访问
QueueTraverse(Q)Q巳存在且非空从队头到队尾,依次对Q的每个数据元素访问

循环队列一一队列的顺序表示和实现

        和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队 列头到队列尾的元素之外,尚需附设两个整型变最 front 和 rear分别指示队列头元素及队列尾元素 的位置(后面分别称为头指针和尾指针)。

//----- 队列的顺序存储结构-----
#define MAXQSIZE 100 
typedef struct 
{ 
QElemType *base; 
int front; 
int rear;
} SqQueue; 
顺序分配的队列中头、尾指针和元素之间的关系

假设当前队列分配的最大空间为 6, 则当队列处于如图所示的状态时不可再继续插入新的队尾元素,否则会出现溢出现象, 即因数组越界而导致程序的非法操作错误。 事实 上,此时队列的实际可用空间并未占满,所以这种现象称 为 “假溢出"。

这是由 "队尾入队,队头出队” 这种受限制 的操作造成的。 怎样解决这种 “假溢出” 问题呢? 一个较巧妙的办法是 亡 Q.rear 将顺序队列变为一个环状的空间,如图所示,称之为循环队列。 

问:对于循环队列不能以头、尾指针的值是否相同来判别队列空间是 “满 ” 还是 “空 ”。 在这种情况下, 如何区别队满还是队空呢?

少用一个元素空间, 即队列空间大小为m时,有m-1个元素就认为是队满。这样判断队 空的条件不变, 即当头、 尾指针的值相同时, 则认为队空;而当尾指针在循环意义上加1后是等 千头指针, 则认为队满。 因此, 在循环队列中队空和队满的条件是:

队空的条件: Q.front = Q.rear

队满的条件: (Q rear+ 1)%M心CQSIZE = Q.front

循环队列的初始化

循环队列的初始化操作就是动态分配一个预定义大小为 MAXQSIZE 的数组空间

【算法步骤】

  1. 为队列分配一个最大容量为 MAXSIZE 的数组空间, base指向数组空间的首地址
  2. 头指针和尾指针置为零, 表示队列为空

【算法实现】

Status InitQueue (SqQueue &Q) 
{//构造一个空队列Q
Q.base=new QElemType[MAXQSIZE]   //为队列分配一个最大容扯为 MAXSIZE 的数组空间
if(!Q.base) exit(OVERFLOW);       //存储分配失败
Q.front=Q.rear=O;        //头指针和尾指针置为零, 队列为空
return OK;
}

求队列长度

对于非循环队列,尾指针和头指针的差值便是队列长度,而对千循环队列,差值可能为负数, 所以需要将差值加上MAXQSIZE, 然后与MAXQSIZE求余

【算法实现】

int QueueLength(SqQueue Q) 
{//返回Q的元素个数, 即队列的长度
return(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE; 
}

循环队列的入队

入队操作是指在队尾插入一个新的元素

【算法步骤】

  1. 判断队列是否满,若满则返回ERROR
  2. 将新元素插入队尾
  3. 队尾指针加1

【算法实现】

Status EnQueue (SqQueue &Q, QElemType e) 
{//插入元素 e 为 Q 的新的队尾元素
if ((Q. rear+l) %MAXQSIZE==Q. front)     //尾指针在循环意义上加1后等于头指针, 表明队满
return ERROR; 
Q.base[Q.rear]=e;               //新元素插入队尾
Q.rear=(Q.rear+l)%MAXQSIZE;         //队尾指针加1 
return OK; 
}

循环队列的出队

出队操作是将队头元素删除

【算法步骤】

  1. 判断队列是否为空, 若空则返回ERROR
  2. 保存队头元素
  3. 队头指针加1

【算法实现】

Status DeQueue (SqQueue &Q, QElemType &e) 
{//删除Q的队头元素, 用 e 返回其值
if(Q.front==Q. rear) return ERROR; //队空
e=Q.base[Q.front]; //保存队头元素
Q.front=(Q.front+1)%MAXQSIZE; //队头指针加1
return OK;

取循环队列的队头元素

当队列非空时, 此操作返回当前队头元素的值, 队头指针保持不变

【算法实现】

SElemType GetHead(SqQueue Q) 
{//返回Q的队头元素,不修改队头指针
if(Q. front! =Q. rear)         //队列非空
return Q.base[Q.front];          //返回对头的元素的值,对头指针不变
}

链队——对列的链式表示和实现

链队列示意图

链队的操作即为单链表插入和删除操作的特殊情况, 只是需进一步修改尾指针或头指针。 下 面给出链队初始化、 入队、 出队操作的实现,具体如下:

//----- 队列的链式存储结构-----

typedef struct QNode {
       QElemType data; 
       struct QNode *next; 
}QNode, *QueuePtr; 
typedef struct 
{
      QueuePtr front; 
      QueuePtr rear; 
}LinkQueue;



链队的初始化

链队的初始化操作就是构造一个只有一个头结点的空队

【算法步骤】

  1. 生成新结点作为头结点, 队头和队尾指针指向此结点
  2. 头结点的指针域置空

【算法实现】

Status InitQueue (LinkQueue &Q) 
{//构造一个空队列 Q
Q.front=Q.rear=new QNode;
Q.front->next=NULL;
return OK;
}

链队的入队

和循环队列的入队操作不同的是,链队在入队前不需要判断队是否满,需要为入队元素动态 分配一个结点空间

【算法步骤】

  1. 为入队元素分配结点空间,用指针p指向
  2. 将新结点数据域置为e
  3. 将新结点插入到队尾
  4. 修改队尾指针为p

【算法实现】

Status EnQueue (LinkQueue &Q, QElemType e) 
{//插入元素e为Q的新的队尾元素
p=new QNode; //为人队元素分配结点空间,用指针p指向
p->data=e; //将新结点数据域置为e
p->next=NULL; Q. rear->next=p; //将新结点插入到队尾
Q.rear=p; //修改队尾指针
return OK; 
}

链队的出队

和循环队列一样,链队在出队前也需要判断队列是否为空,不同的是,链队在出队后需要释 放出队头元素的所占空间

【算法步骤】

  1. 判断队列是否为空,若空则返回ERROR
  2. 临时保存队头元素的空间,以备释放
  3. 修改队头指针,指向下一个结点
  4. 判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值, 指向头结点
  5. 释放原队头元素的空间

【算法实现】

Status DeQueue(LinkQueue &Q,QElemType &e) 
{//删除Q的队头元素, 用e返回其值
if(Q.front==Q.rear) return ERROR; 
p=Q.front->next; 
e=p->data; 
Q.front->next=p->next;
if(Q.rear==p) Q.rear=Q.front; 
delete p; 
return OK;
}

取链队的队头元素

与循环队列一样,当队列非空时,此操作返回当前队头元素的值,队头指针保持不变

【算法实现】

SElemType GetHead{LinkQueue Q) 
{//返回Q的队头元素, 不修改队头指针
if(Q.front!=Q.rear) //队列非空
return Q.front->next->data; //返回队头元素的值,队头指针不变
}

总结

(1)栈是限定仅在表尾进行插入或删除的线性表,又称为后进先出的线性表。栈有两种存储 表示,顺序表示(顺序栈) 和链式表示(链栈)。栈的主要操作是进栈和出栈,对千顺序栈的进栈 和出栈操作要注意判断栈满或栈空。

(2) 队列是一种先进先出的线性表。它只允许在表的一端进行插入, 而在另一端删除元素。 队列也有两种存储表示,顺序表示(循环队列)和链式表示(链队)。队列的主要操作是进队和出 队,对于顺序的循环队列的进队和出队操作要注意判断队满或队空。凡是涉及队头或队尾指针的 修改都要将其对MAXQSIZE求模。

(3) 栈和队列是在程序设计中被广泛使用的两种数据结构,其具体的应用场景都是与其表示 方法和运算规则相互联系的。

队列
逻辑结构和线性表一样,数据元素之间存在一对一的关系和线性表一样,数据元素之间存在一对一的关系
存储结构

顺序存储:

存储空间预先分配,可能会导致空间闲置或栈满溢出现象;数据元素个数不能自由扩充

链式存储:

动态分配, 不会出现闲置或栈满溢出现象;数据元素个数可以自由扩充

顺序存储(常设计成循环队列形式):

存储空间预先分配,可能会导致空间闲置或队满溢出现象;数据元素个数不能自由扩充

链式存储:

动态分配, 不会出现闲置或队满溢出现象;数据元素个数可以自由扩充

运算规则插入和删除在表的一端(栈顶)完成,后进先出插入运算在表的一端(队尾)进行,删除运算在表的另一端(队头), 先进先出

数据结构基础讲解(四)——栈专项练习-CSDN博客

————由于博主还是大三的在读生,时间有限,每天会不定时更新一些学习经验和一些32的项目,如果喜欢就点点关注吧,大佬们!!!!———— 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

樱娆π(准备保研版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值