数据结构实验4.2:循环队列的基本操作


一,问题描述

(1)初始化队列:创建一个空的循环队列,设置队列的头指针 front 和尾指针 rear 到合适的初始位置(通常 frontrear 都初始化为 0),并分配足够的内存空间来存储队列元素。
(2)进队操作:将新的元素添加到循环队列中。首先检查队列是否已满(通过判断队满条件),若未满,则将元素插入到尾指针 rear 所指的位置,并更新尾指针(根据循环队列的规则,可能需要对尾指针进行取模运算以实现循环)。
(3)出队操作:从循环队列中移除并返回队头元素。首先检查队列是否为空(通过判断队空条件),若不为空,则取出队头指针 front 所指的元素,然后更新队头指针(同样可能需要对队头指针进行取模运算)。
(4)判断队空:通过比较队头指针 front 和队尾指针 rear 的值来判断队列是否为空。若 frontrear 相等,则队列为空。
(5)判断队满:由于循环队列中 frontrear 相等时既可能表示队空也可能表示队满,所以通常采用两种方法来判断队满:一是设置一个标志位来记录队列的状态;二是牺牲一个存储单元,当 (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. 将 frontrear 初始化为 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,编写程序运行后的效果。
在这里插入图片描述