一.队列的顺序实现,初始化操作以及判断队列是否为空:
1.图解:
2.代码:
cpp
#include<stdio.h>
#define MaxSize 10 //定义一个队列最多存储的元素个数
typedef struct
{
int data[MaxSize]; //用静态数组存放队列元素
int front; //队头指针,队头删除元素
int rear; //队尾指针,队尾插入元素
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q)
{
//初始时,队头和队尾指针都指向0
Q.front=0;//对头一开始就为0即第一个位置
Q.rear=0;//队尾指针指向下一个插入元素的位置,一开始没元素,下一个当然插在第一个位置即0索引处
}
//判断队列是否为空
bool QueueEmpty(SqQueue Q)
{
if( Q.rear==Q.front ) //Q.rear==Q.front为队空条件
{
return true; //代表队列为空
}
else
{
return false; //代表队列不为空
}
}
int main()
{
SqQueue Q; //声明一个队列(顺序存储)
InitQueue(Q);
//后续操作。。。
return 0;
}
二.队尾元素入队操作(添加数据元素):
1.图解:
a.判断队列是否已满:
b.举例,假设队尾指针指向9:
c.添加元素后:
d.队尾指针进行Q.rear = (Q.rear+1)%MaxSize操作后:对队列最大存储空间取模求出还能存几个元素
e.由于对队尾指针进行的操作是取余运算,会不断地从上到下的循环(比如除以3,余数只会是0,1,2),因此形成了一个闭环:
f.上述就是一个循环队列 ,循环队列还可以解决如下的队列假溢出的情况:
g.继续刚才的例子,此时还有空闲的空间,因此可以继续插入新的数据元素:
h.同时需要队尾指针不断的后移:
i.当队列只剩最后一个存储空间时,就认为此时队列已经满了:
可能会问,此时不是还剩一个存储空间吗,为什么认为满了呢,但需要注意的是,初始化队列时,队头指针和队尾指针是指向了同一个位置,因此判断是否队列已经满了,也需要看队头指针和队尾指针是否指向了同一个位置
(注:队尾指针指向下一个插入元素的位置)
j.总结:
2.代码:
cpp
#include<stdio.h>
#define MaxSize 10 //定义一个队列最多存储的元素个数
typedef struct
{
int data[MaxSize]; //用静态数组存放队列元素
int front; //队头指针,队头删除元素
int rear; //队尾指针,队尾插入元素
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q)
{
//初始时,队头和队尾指针都指向0
Q.front=0;//对头一开始就为0即第一个位置
Q.rear=0;//队尾指向下一个插入元素的位置,一开始没元素,下一个当然插在第一个位置即0索引处
}
//判断队列是否为空
bool QueueEmpty(SqQueue Q)
{
if( Q.rear==Q.front ) //Q.rear==Q.front为队空条件
{
return true; //代表队列为空
}
else
{
return false; //代表队列不为空
}
}
//入队
bool EnQueue(SqQueue &Q,int x)
{
if( (Q.rear+1)%MaxSize==Q.front )
{
return false;//此时队满,返回false
}
//此时队没满
Q.data[ Q.rear ] = x;
/*新元素插入队尾,应该插在Q.rear处,
因为Q.rear队尾指针指向下一个插入元素的位置,而新插入的x刚好就要在
下一个插入元素的位置*/
Q.rear = (Q.rear+1)%MaxSize; //队尾指针加一取模
return true;
}
int main()
{
SqQueue Q; //声明一个队列(顺序存储)
InitQueue(Q);
//后续操作。。。
return 0;
}
三.队头元素出队操作(删除数据元素):
1.图解:
注:这里x有&,调用完函数后x也就跟着改变了 ,x就是被删除的那个元素,队头指针后移就相当于删除了一个元素:
a.Q.front = (Q.front+1)%MaxSize,也需要对MaxSize取模,这样才能让front循环移动:
b.每次出队的都是front指针所指向的元素即x = Q.data[Q.front],并且队头指针会向后移一位:
c.当队头指针和队尾指针再次指向同一个位置时,此时队列已经被取空,此时不能再进行出队操作:
2.代码:
cpp
#include<stdio.h>
#define MaxSize 10 //定义一个队列最多存储的元素个数
typedef struct
{
int data[MaxSize]; //用静态数组存放队列元素
int front; //队头指针,队头删除元素
int rear; //队尾指针,队尾插入元素
}SqQueue;
//出队(删除一个队头元素,并用x返回)
bool DeQueue(SqQueue &Q,int &x) //这里x有&,调用完函数后x也就跟着改变了
{
if( Q.rear==Q.front ) //首先要判断队列是否为空,因为空队列无法删除元素
{
return false; //此时队列为空
}
//此时队列不为空
x = Q.data[Q.front];//把队头指针指向的元素赋值给变量x
Q.front = (Q.front+1)%MaxSize;//队头指针后移一位,也需要对MaxSize取模,这样才能让front循环移动
return true;
}
int main()
{
return 0;
}
四.查找队列中的元素:
1.图解:
通常只需要查询或者只需要读取队列中队头的元素:
获得队头元素的值即查找元素,用x返回。这里x有&,调用完函数后x也就跟着改变了,变为队头元素; x就是队头元素,获取到队头元素后可以与要查找的元素比较。
2.代码:
cpp
#include<stdio.h>
#define MaxSize 10 //定义一个队列最多存储的元素个数
typedef struct
{
int data[MaxSize]; //用静态数组存放队列元素
int front; //队头指针,队头删除元素
int rear; //队尾指针,队尾插入元素
}SqQueue;
//获得队头元素的值即查找元素,用x返回
/*这里x有&,调用完函数后x也就跟着改变了,变为队头元素;
x就是队头元素,获取到队头元素后可以与要查找的元素比较*/
//相比出队操作,就少了一个Q.front = (Q.front+1)%MaxSize,就不让队头指针后移
bool GetHead(SqQueue Q,int &x)
{
if( Q.rear==Q.front )//需要判断队列是否为空,空队列无法查找元素
{
return false;//队空返回false
}
//此时队列不为空
x = Q.data[Q.front];
return true;
}
int main()
{
return 0;
}
五.判断队列已满,已空:
1.队列此时已有的元素个数计算公式:
(队尾指针+队列最多存储个数-队头指针)%队列最多存储个数
2.方案一:牺牲一个存储空间来判断队列已满,已空
3.方案二:无需牺牲一个存储空间即可判断队列已满,已空
思路:在定义结构体队列时定义一个变量size,用来记录队列当前长度,size初始值为0,因为一开始没元素,
只要有元素入队,size自增;只要有元素出队,size自减
4.方案三:无需牺牲一个存储空间即可判断队列已满,已空
思路:在定义结构体队列时定义一个变量tag,初始化时tag为0,因为一开始没元素,可以认为是删除后才没元素
当tag为0时表示最近一次执行了一次删除操作,
当tag为1时表示最近一次执行了一次插入操作,
六.其他出题方式:
1.如果队尾指针指向最后一个元素而不是下一个元素要插入的位置,那么入队时就需要先让队尾指针后移一个位置,
腾出位置来添加元素,最后再添加元素
2.如果队尾指针指向最后一个元素而不是下一个元素要插入的位置,那么在初始化时,队头指针指向第一个位置,
队尾指针指向最后一个位置->这样的话在元素入队时就会先队尾指针后移一个位置,再取余就可以了
七.总结:
注:静态数组大小已经确定,因此要用模运算(取余运算)来重复地利用静态数组中各个空闲的存储空间。