循环队列的设计与运行
1. 队列
栈和队列有很大的相似性,但各自有着很独特的特征,栈是先进后出,队列是先进先出,队列很像排队就餐。
队列的学习有以下三个过程:
- 顺序队列
顺序队列就是根据先进先出原理构想出来的结构,下边是逻辑图:
这里用两个下标rear和front对入、出进行监控,开始的时候rear=front=0,对于每次进入一个元素,rear++(所以rear一直是指向空的位置),对于每次出去一个元素,front++ - 循环队列
因为队列独特的特征,会出现以下两种溢出的情况:
1)真溢出
2)假溢出
为了弥补队列这个缺陷,会使用循环队列(下边是逻辑图)
但是又会出现另一个问题,对于循环队列,如何判定该队列是空还是满?
- 循环队列情况的判定
请看我的上一篇文章如何判断循环队列是否为空问题。
2.代码部分
好了,啰里吧嗦这么久,我们进入最喜爱的实战部分:
- main函数(主要是对功能的选择访问)
#include"001.h"
int main()
{
int choose = -1;
cout << "本次循环队列服务共有以下几项服务,请选择" << endl << endl;
cout << "1. 循环队列的初始化" << endl;
cout << "2. 求循环队列的长度" << endl;
cout << "3. 循环队列入队" << endl;
cout << "4. 循环队列出队" << endl;
cout << "0. 退出" << endl<<endl;
SqQueue Q; //定义一个顺序栈Q
QElemType e; //定义一个结构体元素
while (choose != 0)
{
do { //对choose的值进行判断
cin >> choose;
if (choose < 0 && choose>4) cout << "您输入的数据不再本次服务之内,请重新输入:" << endl;
} while (choose < 0 && choose>4);
switch (choose){
case 1: //循环队列的初始化
if (InitQueue(Q)) cout << "循环队列初始化成功" << endl<<endl;
cout << "请继续您的选择:" << endl;
break;
case 2: //求循环队列的长度
cout << "此时循环队列的长度为:" << QueueLength(Q) << endl << endl;
cout << "请继续您的选择:" << endl;
break;
case 3: //循环队列入队
cout << "请依次输入入队元素的姓名和学号:" << endl;
cin >> e.name >> e.number;
if (EnQueue(Q, e)) cout << "该元素入队成功!" << endl;
else cout << "该元素入队失败!" << endl;
cout << "请继续您的选择:" << endl;
break;
case 4: //循环队列出队
if (DeQueue(Q, e)) {
cout << "您此时的出队元素为:" << endl;
cout << e.name << " " << e.number << endl;
}else
cout << "此时队列已空,请入队后重试" << endl;
cout << "请继续您的选择:" << endl;
break;
default:break;
}
}
cout << "感谢您的使用,再见" << endl<<endl;
}
- 001.h函数(包含循环队列的具体函数)
我这个头文件命名极其不规范,见谅,见谅
#pragma once
#include<iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
#define MAXSIZE 100
typedef struct
{
char name[30];
char number[30];
}QElemType;
typedef struct //定义一个队列
{
QElemType* base; //初始化的动态分布存储空间
int front; //出队下标
int rear; //进队下标
}SqQueue;
Status InitQueue(SqQueue& Q) { //循环队列的初始化
Q.base = new QElemType[MAXSIZE];
if (!Q.base) exit(OVERFLOW);
Q.front = Q.rear = 0;
return OK;
}
int QueueLength(SqQueue Q) //求循环队列的长度
{
return(Q.rear - Q.front + MAXSIZE) % MAXSIZE; //Q.rear-Q.front的值可正可负
}
Status EnQueue(SqQueue& Q, QElemType& e) //循环队列入队
{
if ((Q.rear + 1) % MAXSIZE == Q.front) return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXSIZE;
return OK;
}
Status DeQueue(SqQueue& Q, QElemType& e) //循环队列出队
{
if (Q.front == Q.rear) return ERROR;
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXSIZE;
return OK;
}
3. 代码分析
- 关于求循队列的长度,我这里用了这么一条:
return(Q.rear - Q.front + MAXSIZE) % MAXSIZE;
因为模的存在,所以Q.rear和Q.front大小难以确定,相加减很难确定是正是负,这里用这个方法有效解决正负问题且避免溢出(括号里的原理类似于两位数相减:个位不足向十位借1;或者说是时钟原理:正转半圈和倒转半圈的时间一样)
- 在循环队列出队时要判断队列是否为空,否则将会出现乱码
if (DeQueue(Q, e)) {
cout << "您此时的出队元素为:" << endl;
cout << e.name << " " << e.number << endl;
}else
cout << "此时队列已空,请入队后重试" << endl;
4. 运行结果
笔记最后,记录一下今天的心情~