辛苦手码不易, 如若有帮助烦请不吝收藏点赞 😃
静态实现:
#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
Elemtype data[MaxSize];//用静态数组存放队列元素
int front,rear;//队头指针和队尾指针
}SqQueue;//Sq 顺序
void testQueue(){
SqQueue Q;//声明一个顺序队列
//........后续操作
}
如上图, 假设队列被分配了五个元素, 则front应指向队头元素(下标0), rear应指向队尾元素的下一个位置, 即插入元素的位置(下标4+1=5)
依照上述逻辑, 在初始化时, 可以让front和rear都指向0, 这同时也可以作为队列判空的标志:
初始化与队列判空:
void InitQueue(SqQueue &Q){//初始化
Q.rear=Q.front=0;//初始时, 队头队尾指针都指向0
}
void testQueue(){
SqQueue Q;//声明一个顺序队列
InitQueue(Q)
//........后续操作
}
bool QueueEmpty(SqQueue Q){//判空
if(Q.rear==Q.front)//队空条件
return ture;
else
return false;
}
入队操作:
#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
Elemtype data[MaxSize];//用静态数组存放队列元素
int front,rear;//队头指针和队尾指针
}SqQueue;//Sq 顺序
//入队(只能从队尾入队)
bool EnQueue(SqQueue &Q,ElemType x){
if((Q.rear+1)%MaxSize==Q.front)//队满条件
return false;//队满则报错
Q.data[Q.rear]=x;//新元素插入队尾
Q.rear=(Q.rear+1)%MaxSize;//队尾指针+1取模
return true;
}
对于取模, 我们假设队列Q现在存储了10个元素, 然后出队了3个元素, 即右图所示, 这时, rear==MaxSize
思考: rear==MaxSize是队满条件吗?
假设Q存储10个元素后, 让3个元素从队头出队, 则现在rear=MaxSize, front=3, 显然队不满, 于是每次入队操作后, 对rear+1取模, 即9+1%10=0, rear指针指向了0, 如此, 则rear指针指向了队头, front指针指向了队尾
于是, 我们可以将这样实现的队列理解为一个循环队列
出队操作&查队头元素:
//删除一个队头元素, 用x返回
bool DeQueue(SqQueue &Q,ElemType &x){
if(Q.rear==Q.front)//判断队空
return false;//队空则报错
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;//队头指针后移:front永远指向第一个存了元素的位置
return true;
}
//获取队头元素的值, 用x返回
bool GetHeadd(SqQueue Q,ElemType &x){
if(Q.rear==Q.front)//判断队空
return false;//队空则报错
x=Q.data[Q.front];
//省略了队头指针后移操作
return true;
}
下面着重研究判断队列空/满的几种实现方案
-
循环队列
队满:
(Q.rear+1)%MaxSize==Q.front
队空:
Q.rear==Q.front
缺点: 浪费一个存储空间–>于是, 下列方案2&3不会浪费存储空间
队列元素个数计算公式:
(rear+MaxSize-front)%MaxSize
-
定义size变量
在队列的静态定义时,定义size变量,记录队列当前长度
#define MaxSize 10
typedef struct{
Elemtype data[MaxSize];
int front,rear;
int size;//在队列的静态定义时,定义size变量,记录队列当前长度
}SqQueue;
//入队成功则size++,出队成功则size--
void InitQueue(SqQueue &Q){//初始化
Q.rear=Q.front=0;//初始时, 队头队尾指针都指向0
size=0;
}
//入队(只能从队尾入队)
bool EnQueue(SqQueue &Q,ElemType x){
if(size==MaxSize)//队满条件
return false;//队满则报错
Q.data[Q.rear]=x;//新元素插入队尾
Q.rear=(Q.rear+1)%MaxSize;//队尾指针+1取模
size++;
return true;
}
//删除一个队头元素, 用x返回
bool DeQueue(SqQueue &Q,ElemType &x){
if(size==0)//判断队空
return false;//队空则报错
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;//队头指针后移:front永远指向第一个存了元素的位置
size--;
return true;
}
-
定义tag变量
思想:
只有删除操作, 才可能导致队空;
只有插入操作, 才可能导致队满;
故:
每次删除操作成功时, 都令tag=0;
每次插入操作成功时, 都令tag=1;
则:
队满:
Q.front==Q.rear&&tag==1
队空:
Q.front==Q.rear&&tag==0
于是–tag变量记录最近进行的是插入/删除操作
#define MaxSize 10
typedef struct{
Elemtype data[MaxSize];
int front,rear;
int tag;//在队列的静态定义时,定义tag变量,记录最近进行的是插入/删除操作
}SqQueue;
void InitQueue(SqQueue &Q){//初始化
Q.rear=Q.front=0;//初始时, 队头队尾指针都指向0
tag=0;
}
//入队(只能从队尾入队)
bool EnQueue(SqQueue &Q,ElemType x){
if(Q.front==Q.rear&&tag==1)//队满条件
return false;//队满则报错
Q.data[Q.rear]=x;//新元素插入队尾
Q.rear=(Q.rear+1)%MaxSize;//队尾指针+1取模
tag=1;
return true;
}
//删除一个队头元素, 用x返回
bool DeQueue(SqQueue &Q,ElemType &x){
if(Q.front==Q.rear&&tag==0)//判断队空
return false;//队空则报错
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;//队头指针后移:front永远指向第一个存了元素的位置
tag=0;
return true;
}
-
队尾指针rear指向队尾元素时
初始化时, 队头指针=0, 队尾指针=MaxSize-1
入队时, 交换rear+1和赋值的顺序
队空:
(Q.rear+1)%MaxSize==Q.front
队满: 两种方案: 1. 牺牲一个存储空间
(Q.rear+2)%MaxSize==Q.front
2.增加辅助变量size/tag
#define MaxSize 10
typedef struct{
Elemtype data[MaxSize];
int front,rear;
}SqQueue;
void InitQueue(SqQueue &Q){//初始化
Q.front=0;//初始时, 队头指针指向0
Q.rear=MaxSize-1;//队尾指针指向n-1
}
//入队(只能从队尾入队)
bool EnQueue(SqQueue &Q,ElemType x){
if((Q.rear+2)%MaxSize==Q.front)//判断队满:1.牺牲一个存储单元: (rear+2)%MaxSize==Q.front 2.增加辅助变量size/tag
return false;//队满则报错
Q.rear=(Q.rear+1)%MaxSize;//队尾指针+1取模
Q.data[Q.rear]=x;//新元素插入队尾
return true;
}
//删除一个队头元素, 用x返回
bool DeQueue(SqQueue &Q,ElemType &x){
if((Q.rear+1)%MaxSize==Q.front)//判断队空
return false;//队空则报错
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;//队头指针后移:front永远指向第一个存了元素的位置
return true;
}