《数据结构打卡》第16天(队列篇)
距离上一次更新隔了也有15天之久了,在家里的这段时间真的过得蛮快的,但是也是昨天跟今天一样,今天跟明天一样,循环往复着;
队列的定义:
- 队列是操作受限的线性表,队列的插入在队尾,队列的删除在队头,
- 队列是先进先出的线性表
1、什么是队列的上溢现象?一般有几种解决方法,试简述之?
答:…
当队列中还有剩余空间,入队时却出现队满的情况,一般是因为队满条件设置不合理造成的,称之为“假溢出”。
总共有三种方法解决队列的假溢出:
方法一:增设一个存储队列元素个数的变量num,当num=0时队空,当num=MaxQSize 时为队满;
方法二:设置一个flag标志,当front =rear且flag =0时,则队空,当front=rear且flag = 1时,则队满。
方法三:采取少用一个存储单元的方式,引入循环队列,则队满时队列中还剩一个空闲单元,即队空条件:front == rear,队满条件:(rear+1) % MaxQSize == front,队列长度为(rear-front+MaxQSize) % MaxQSize。
顺序队列抽象数据类型定义:
typedef struct{
QElemType data[MaxQSize];//定义队列的存储容量,用于存储队列中元素
int front,rear; //队头和队尾指针
}//SqQueue 顺序队的类型
1.顺序队列的要素
队空条件:Q.front == Q.rear
队满条件:Q.front == MaxQSize -1(数组的最大下标)
队满条件:也可以是Q->rear==Q->front= =n
其实和栈的栈空栈满条件很相似,
栈空是s.top == -1;
栈满是s.top == MaxSize -1;
顺序队的初始化
void InitQueue(SqQueue &q){
Q=(Squeue * )malloc(sizeof(Squeue)); //分配顺序队列
Q.front = Q.rear = -1;
}
顺序队的入队EnQueue(&Q,e):
入队:队尾指针先加适用于队尾指针指向最后一个元素的下一个位置:而尾指针后加的情况适用于队尾指针指向最后一个元素的当前位置。
void EnQueue(SqQueue &Q,QElemType e){
if(Q.front == MaxQSize-1) //1.判断顺序队是否队满
return error;
Q.rear++; //2.先移动队尾指针
Q.data[Q.rear] = e; //3.再入队元素
}
顺序队的出队DeQueue(&Q,&e):
void DeQueue(SqQueue &Q,QElmeType &e){
if(Q.front == Q.rear) //1.判断队列是否为空
return error;
Q.front++ //2.先移动队头指针
e = Q.data[Q.front] //2.再用e出队元素
}
销毁队列,判断队空。
void DestroyQueue(SqQueue &Q){
free(Q)
}
bool QueueEmpty(SqQueue &Q){
return(Q.front == Q.rear) //若队列为空返回真,若不为空返回假
}
2.循环队列的三要素
队空条件:Q.front == Q.rear
队满条件:(Q.rear+1) % MaxQSize == Q.front
队列长度:(Q.rear-Q.front+MaxQSize) % MaxQSize
入队 rear指针循环增1:Q.rear = (Q.rear+1) % MaxQSize
出队 front指针循环增1:Q.front = (Q.front+1) % MaxQSize
//一般情况下,循环队列采用队头front指向当前第一个元素的位置,rear指向最后一个元素的下一个位置。
循环队列的初始化
void InitQueue(SqQueue &Q){
Q = (SqQueue * )malloc(sizeof(SqQueue )) //分配队列空间
Q.front = Q.rear = 0; //队头队尾指针指向一起
//其实循环队列和顺序队列的初始化是一样的,不过教材上硬是要把顺序队列中队头队尾指针设为-1,而循环队列中则把队头队尾指针在初始化时指向0
}
循环队列的入队、出队、求队列长度:
这里入队和出队统一按照先移动队头或队尾指针,然后再入队或出队元素。
Status EnQueue(SqQueue &Q,QElemType Q){
if((Q.rear+1) % MaxQSize == Q.front) //1.判断队满
return error;
Q.rear = (Q.rear+1) % MaxQSize; //2.先队尾指针循环增1
Q.data[Q.rear] = e; //3.后元素e入队
return ok;
}
Status DeQueue(SqQueue &Q,QElemType &Q){
if(Q.front == Q.rear) //1.判断队列是否为空
return error;
Q.front = (Q.front+1) % MaxQSize //2.先队头指针循环增1
e = Q.data[Q.front]; //3.后用e取出队头元素
return ok;
}
int LengthQueue(SqQueue &Q){
return (Q.rear-Q.front+MaxQSize) % MaxQSize
//(指向队尾元素下一位置rear指针 - 队头元素指针 + 队列最大容量) % 队列最大容量 = 队列长度
}
3.链式队列的要素
- 队空的条件为:Q.rear->next == Null
- 和链式栈一样,不考虑队满的情况
链式队列的入队:
①生成新结点存放元素e,由p指针指向。
②将结点p从队尾插入,再由队尾指针指向它。
Status EnQueue(LinkQueue &Q,QElmeType e){
QNode = *p; //声明p指针,用于元素入队
p = (QNode * )malloc(sizeof(QNode)); //1.p指向新创建的结点
//或 p = new QNode;
p->data = e; //p的data域赋值
p->next = Null; //p结点插入在队尾,所以next域一定要置空
//链式队的入队不考虑队满的情况
if(Q.rear->next == Null) //若队列为空
Q.front=Q.rear = p; //2.则队头队尾指针均指向p结点
else{ //队列中存在结点
//以下两步才是最重要的
Q.rear->next = p; //3.rear指针先链接p结点
Q.rear = p; //4.然后rear指针指向新插入的尾结点
}
return ok;
}
链式队列的出队:
①使用元素e取出队头元素,
②然后队头指针后移,指向下一结点。
Status DeQueue(LinkQueue &Q,ElemType &e){
QNode = *p; //声明p指针,用于元素出队
if(Q.rear->next == Null) //判断链队列是否为空
return error;
p=Q.front->next //1.先让P结点指向头结点的下一个结点
e=p->data; //2.再用e返回p结点data域的值
Q.front->next = p->next; //3.修改指针,头指针指向将要被删除
//结点的后继结点。
delete p; //4.删除p所指结点
}