一,问题描述
(1)初始化队列:创建一个空的循环队列,设置队列的头指针 front
和尾指针 rear
到合适的初始位置(通常 front
和 rear
都初始化为 0),并分配足够的内存空间来存储队列元素。
(2)进队操作:将新的元素添加到循环队列中。首先检查队列是否已满(通过判断队满条件),若未满,则将元素插入到尾指针 rear
所指的位置,并更新尾指针(根据循环队列的规则,可能需要对尾指针进行取模运算以实现循环)。
(3)出队操作:从循环队列中移除并返回队头元素。首先检查队列是否为空(通过判断队空条件),若不为空,则取出队头指针 front
所指的元素,然后更新队头指针(同样可能需要对队头指针进行取模运算)。
(4)判断队空:通过比较队头指针 front
和队尾指针 rear
的值来判断队列是否为空。若 front
和 rear
相等,则队列为空。
(5)判断队满:由于循环队列中 front
和 rear
相等时既可能表示队空也可能表示队满,所以通常采用两种方法来判断队满:一是设置一个标志位来记录队列的状态;二是牺牲一个存储单元,当 (rear + 1) % 队列容量 == front
时表示队满。
(6)调用进队函数建立一个队列:通过多次调用进队函数,将多个元素依次添加到循环队列中,构建出一个完整的循环队列。在添加元素过程中,要注意队满情况的处理。
(7)输出队列中的所有元素:遍历循环队列,从队头指针 front
开始,按照队列的顺序输出每个元素,直到遇到队尾指针 rear
(或者根据循环队列的特性进行相应的遍历)。
二,基本要求
(1)设计循环队列的存储结构:
typedef int QElemType;
typedef struct {
QElemType *base; // 用于存储队列元素的数组指针
int front; // 队头指针,指向队头元素的位置
int rear; // 队尾指针,指向队尾元素的下一个位置
int capacity; // 队列的容量
}SqQueue;
(2)设计基于循环队列的几种基本操作的算法:
- 初始化队列算法:
1. 分配内存空间给base
数组,大小为指定的队列容量。
2. 将front
和rear
初始化为 0。
3. 设置capacity
为队列的容量。 - 进队操作算法:
1. 判断队列是否已满(使用判断队满的方法)。
2. 若未满,将元素存储到base[rear]
位置。
3. 更新rear
为(rear + 1) % capacity
。 - 出队操作算法:
1. 判断队列是否为空(使用判断队空的方法)。
2. 若不为空,取出base[front]
的元素。
3. 更新front
为(front + 1) % capacity
。 - 判断队空算法:返回
front == rear
的结果。 - 判断队满算法:根据选择的判断队满方法(如
(rear + 1) % capacity == front
或通过标志位)返回相应的结果。 - 建立队列算法:
1. 初始化一个空的循环队列。
2. 依次调用进队函数,将元素添加到队列中。 - 输出队列元素算法:
1. 从front
开始,按照循环队列的规则遍历队列。
2. 输出每个元素,直到遇到rear
(或根据循环特性进行判断)。
(3)在参考程序中的下划线处填写适当的语句,完成参考程序:仔细分析参考程序的逻辑,根据设计的存储结构和算法,在相应位置补充缺失的代码,使程序完整且能正确运行。
(4)设计测试用例,上机调试、测试参考程序,记录测试结果,对结果进行分析:
- 设计测试用例:包括空队列的操作(如判断队空、出队)、正常队列的进队和出队(多次进队和出队操作)、边界情况(队满时进队、队空时出队)等。
- 上机调试:运行程序,输入测试用例,观察程序的运行情况,检查是否有错误或异常。
- 记录测试结果:记录每个测试用例的输入和输出,以及程序的运行状态(如是否崩溃、是否得到预期结果)。
- 分析结果:根据测试结果,分析程序的正确性、性能和稳定性。检查是否存在逻辑错误、边界条件处理不当等问题,并进行相应的修改和优化。
(5)要求每完成一个步骤就必须及时输出队列中元素以便观察操作结果:在初始化队列、进队、出队、建立队列等操作完成后,立即调用输出队列元素的函数,显示当前队列的内容,方便直观地了解操作对队列的影响。
三,循环队列存储结构设计
typedef int QElemType;
typedef struct {
QElemType *base;
int front;
int rear;
int capacity;
}SqQueue;
解释:
base
指针用于指向存储队列元素的数组,通过动态分配内存来存储队列中的数据。front
表示队头指针,指向队头元素在数组中的位置。rear
表示队尾指针,指向队尾元素的下一个位置(在循环队列的逻辑中)。capacity
记录队列的容量,即数组能够存储的元素的最大数量。
四,示例代码
#include<stdio.h>
#include<malloc.h>
#define MAXSIZE 10
#define OK 1
#define ERROR 0
typedef int Status;
typedef int QElemType;
typedef struct {
QElemType* base;
int front;
int rear;
}SqQueue;
Status InitQueue(SqQueue& Q) {
// 队列初始化
Q.base = (QElemType*)malloc(MAXSIZE * sizeof(QElemType));
if (!Q.base) return ERROR;
Q.front = Q.rear = 0; // 1. 初始化队头和队尾指针都为0
return OK;
}
Status EnQueue(SqQueue& Q, QElemType e) {
// 将元素e插入队列Q的队尾
if ((Q.rear + 1) % MAXSIZE == Q.front) return ERROR; //若队列满,进队失败 2. 判断队列是否已满
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXSIZE; // 修改队尾指针 3. 更新队尾指针,实现循环队列的逻辑
return OK;
}
Status DeQueue(SqQueue& Q, QElemType& e) {
//删除队列Q的队首元素,并用e带回
if (Q.front == Q.rear) return ERROR; // 若队空,出队失败 4. 判断队列是否为空
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXSIZE; //修改队首指针 5. 更新队首指针,实现循环队列的逻辑
return OK;
}
void OutputQueue(SqQueue Q) // 输出队列中元素
{
while (Q.front != Q.rear) {
// 如果队列非空
printf("%d ", Q.base[Q.front]);
Q.front = (Q.front + 1) % MAXSIZE;
}
printf("\n");
}
void main()
{
SqQueue Q;
InitQueue(Q);
int op, x;
while (1)
{
printf("请选择操作:1.进队 2.出队 0.退出==>");
scanf("%d", &op);
switch (op) {
case 0: // 退出
return;
case 1: // 进队
printf("请输入进队元素:"); // 整数
scanf("%d", &x);
if (!EnQueue(Q, x)) // 进队失败 6. 调用进队函数,若返回值为假则进队失败
printf(" 队列满!\n");
else {
printf("进队成功,队内元素为:\n");
OutputQueue(Q);
}
break;
case 2: // 出队
if (DeQueue(Q, x)) {
// 出队成功 7. 调用出队函数,若返回值为真则出队成功
printf("出队元素为:[%d],队内元素为:\n", x);
OutputQueue(Q);
}
else
printf(" 队已空!\n");
break;
}
}
}
五,实验操作
1.双击程序图标,启动程序。
2.新建项目。
3.选择”空项目“——输入项目名称——单击”确认“按钮。
4.右击”源文件“——”添加“——选择”新建项“。
5.选择”C++文件“——输入文件名——单击”添加“按钮。
6.编写代码。
7.编译代码。
8.查看编译结果。
9.单击绿色小三角,运行项目。
六,运行效果
1,实验要求的效果。
2,编写程序运行后的效果。