前言 代码仓库链接
本项目已经开源在github仓库:zzu_DataStructure_Experiment
🐑 zzu_DataStructure_Experiment:是一个用于学习和练习核心数据结构的代码仓库。它包含zzu的所有数据结构实验,涉及数组、链表、栈、队列、树、图等多种数据结构的实现、示例和测试用例,帮助读者强化编程能力并提升算法思维。
♥️ 如果你觉得项目对你有用,请留下一个 ⭐️ Star来支持作者,不胜感激~ ♥️
1 实验目的
熟练掌握栈和队列的抽象数据类型,能在相应的应用问题中正确选用它们,熟练掌握栈和队列的实现方法(顺序和链式),两种存储结构和基本操作的实现算法,注意空和满的判断条件及它们的描述方法,掌握循环队列与其它顺序结构实现上的不同及解决办法,熟悉各种队列的基本操作在循环队列上的实现。
2 实验内容
- 用队列实现形如a + b@b + a# 的中心对称的字符序列的检验。
- 选择合适的存储结构(循环队列)表示队列,解决队空、队满判断条件相同的矛盾,实现基于循环队列的存储结构的基本操作,初始化、队空/满判断,入队、出队、取队头元素、求队列长度等,对所写出的算法进行时间复杂度分析。
3 实验操作
3.1 函数声明和队列数据结构定义
和之前的实验不同,这里的实验在单个文件(
exp04.cpp)完成。
代码首先定义了循环队列(Circular Queue)的基本操作及其相关功能。循环队列是一种特殊的队列结构,利用数组存储数据元素,通过头指针(front)和尾指针(rear)的移动实现“首尾相接”的循环存储方式。
代码中定义了循环队列的基本结构体 sqqueue,并声明了一系列操作函数,包括队列的初始化、入队、出队、判断空/满、获取队头元素、销毁队列等。此外,还声明了一个名为 CenterMatch 的函数,用于判断一个字符串是否为中心对称(回文)序列。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define maxqsize 20
typedef char qelemtype;
typedef int status;
//约定以少用一个元素空间,以“队列头指针在队列尾指针的下一位置”作为队列满的标志
typedef struct {
qelemtype* base;
int front;
int rear;
}sqqueue;
//1.初始化队列
status InitQueue(sqqueue& Q);
//2.求队列长度
int QueueLength(sqqueue Q);
//3.入队列
status EnQueue(sqqueue& Q, qelemtype e);
//4.队前元素出队列
status DeQueueFront(sqqueue& Q, qelemtype& e);
//5.队后元素出队列
status DeQueueRear(sqqueue& Q, qelemtype& e);
//6.判断是否队空
status QueueEmpty(sqqueue Q);
//7.判断是否队满
status QueueFull(sqqueue Q);
//8.获取队头元素
status GetHead(sqqueue Q, qelemtype& e);
//9.摧毁队列
status DestroyQueue(sqqueue& Q);
//中心对称的字符序列的检验
int CenterMatch(char* str);
2️⃣ 接着函数声明部分定义了循环队列的基本操作和扩展功能(中心对称检查):
| 序号 | 函数声明 | 功能说明 |
|---|---|---|
| 1 | status InitQueue(sqqueue& Q); | 初始化队列,分配存储空间并设置头尾指针 |
| 2 | int QueueLength(sqqueue Q); | 返回队列中元素的个数 |
| 3 | status EnQueue(sqqueue& Q, qelemtype e); | 将元素 e 插入队列尾部(入队) |
| 4 | status DeQueueFront(sqqueue& Q, qelemtype& e); | 删除队头元素并用 e 返回(前端出队) |
| 5 | status DeQueueRear(sqqueue& Q, qelemtype& e); | 删除队尾元素并用 e 返回(后端出队) |
| 6 | status QueueEmpty(sqqueue Q); | 判断队列是否为空 |
| 7 | status QueueFull(sqqueue Q); | 判断队列是否已满 |
| 8 | status GetHead(sqqueue Q, qelemtype& e); | 获取队头元素(不出队) |
| 9 | status DestroyQueue(sqqueue& Q); | 销毁队列,释放空间 |
| 10 | int CenterMatch(char* str); | 判断字符串是否为中心对称(回文)序列 |
3.2 队列的基本操作实现
🧩 3.2.1 基本操作1 初始化队列
该函数用于创建并初始化循环队列。通过 malloc 动态分配一段大小为 maxqsize 的存储空间给 Q.base,并将 front 和 rear 都置为 0,表示队列为空。执行成功返回 OK,若内存分配失败则退出程序。具体代码如下:
//1.初始化栈
status InitStack(sqstack& S) {
S.base = (elemtype*)malloc(stackinitsize * sizeof(elemtype));
if (!S.base)exit(OVERFLOW);
S.top = S.base;
S.stacksize = stackinitsize;
return OK;
}
🧩 3.2.2 基本操作2 求队列长度
该函数通过 (Q.rear - Q.front + maxqsize) % maxqsize 计算当前队列中元素的个数。利用取模操作,能在循环数组中正确计算长度,无论 rear 是否“绕回”数组开头。具体代码如下:
//2.求队列长度
int QueueLength(sqqueue Q) {
return (Q.rear - Q.front + maxqsize) % maxqsize;
}
🧩 3.2.3 基本操作3 入队列
该函数用于将元素 e 插入队列尾部。首先判断 (Q.rear + 1) % maxqsize == Q.front 是否成立,若为真则表示队列已满,入队失败。否则,将元素存入 Q.base[Q.rear],然后将 rear 向后移动一个位置(循环意义上)。具体代码如下:
//3.入队列
status EnQueue(sqqueue& Q, qelemtype e) {
if ((Q.rear + 1) % maxqsize == Q.front)return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % maxqsize;
return OK;
}
🧩 3.2.4 基本操作4 队前元素出队列
该函数用于删除队头元素并将其保存到变量 e 中。若 Q.front == Q.rear 表示队列为空,出队失败。否则,将队头元素取出,然后使 front 前移一位(循环方式),实现出队。具体代码如下:
//4.队前元素出队列
status DeQueueFront(sqqueue& Q, qelemtype& e) {
if (Q.rear == Q.front)return ERROR;
e = Q.base[Q.front];
Q.front = (Q.front + 1) % maxqsize;
return OK;
}
🧩 3.2.5 基本操作5 队后元素出队列
该函数实现从队尾删除一个元素并返回它。如果队列为空则返回 ERROR。否则取出尾部元素 Q.base[Q.rear - 1],再将 rear 向前移动一位。具体代码如下:
//5.队后元素出队列
status DeQueueRear(sqqueue& Q, qelemtype& e) {
if (Q.rear == Q.front)return ERROR;
e = Q.base[Q.rear - 1];
Q.rear = (Q.rear - 1) % maxqsize;
return OK;
}
🧩 3.2.6 基本操作6 判断是否队空
该函数通过 Q.front == Q.rear判断队列是否为空。若队列为空,返回 OK(1);否则返回 ERROR(0)。具体代码如下:
//6.判断是否队空
status QueueEmpty(sqqueue Q) {
if (Q.front == Q.rear)return OK;
else
return ERROR;
}
🧩 3.2.7 基本操作7 判断是否队满
当 (Q.rear + 1) % maxqsize == Q.front 时,表示队列已满。此时尾指针“追上”头指针的前一位置,返回 OK;否则返回 ERROR。具体代码如下:
//7.判断是否队满
status QueueFull(sqqueue Q) {
if ((Q.rear + 1) % maxqsize == Q.front)return OK;
else
return ERROR;
}
🧩 3.2.8 基本操作8 获取队头元素
该操作用于读取但不删除队头元素。若队列为空则返回 ERROR,否则将 Q.base[Q.front] 赋值给 e 并返回 OK。具体代码如下:
//8.获取队头元素
status GetHead(sqqueue Q, qelemtype& e) {
if (Q.rear == Q.front)return ERROR;
e = Q.base[Q.front];
return OK;
}
🧩 3.2.9 基本操作9 摧毁队列
该函数用于释放队列占用的内存空间。若 Q.base 存在,则先释放它,并将 front、rear 置空(即 NULL),防止野指针。销毁后返回 OK。具体代码如下:
//9.摧毁队列
status DestroyQueue(sqqueue& Q) {
if (Q.base) {
Q.front = Q.rear = NULL;
free(Q.base);
}
return OK;
}
👍 3.3 实验内容实现:中心对称的字符序列的检验
CenterMatch(char* str) 函数用于判断一个特定格式的字符串是否为中心对称(回文)序列。程序先初始化循环队列,将字符串中 ‘@’ 前和 ‘@’ 后、‘#’ 前的字符依次入队,然后从队头和队尾分别取出字符进行比较;若任意一对字符不相等则说明不对称,立即结束;若所有字符均成对相等,最终队列为空,则说明该字符串中心对称,函数返回 OK,否则返回 ERROR。具体代码如下:
//栈的括号匹配检验
status CheckMatch_Brackets(char* str) {
sqstack S;
InitStack(S);
ClearStack(S);
int len = strlen(str);
elemtype e;
int i;
for (int i = 0; i < len; i++) {
switch (str[i]) {
case '{':
case '[':
case '(':
Push(S, str[i]);
break;
case '}':
if (S.top == S.base)
return ERROR;
Pop(S, e);
if (e != '{')
return ERROR;
break;
case ']':
if (S.top == S.base)
return ERROR;
Pop(S, e);
if (e != '[')
return ERROR;
break;
case ')':
if (S.top == S.base)
return ERROR;
Pop(S, e);
if (e != '(')
return ERROR;
break;
default:
break;
}
}
if (S.top != S.base)return ERROR;
return OK;
}
3.6 主函数测试实现
主函数用于对前面实现的队列基本操作和应用函数进行综合测试。程序首先初始化一个循环队列 Q,依次入队元素 ‘a’、‘b’、‘c’、‘d’,并在每次操作后输出当前队列长度,然后判断队列是否为空。接着进行多次出队操作,包括从队头和队尾删除元素,并显示出队的字符及当前队列长度,再次检查队列是否为空,最后销毁队列以释放内存。随后,程序进入中心对称检测部分,提示用户输入一个以 ‘@’ 为分隔符、‘#’ 为结尾标志的字符串,通过调用 CenterMatch() 函数判断其是否为中心对称序列,并输出相应结果。具体实现代码如下:
int main() {
sqqueue Q;
qelemtype e;
InitQueue(Q);
cout << "-----------循环队列的基本操作测试:----------" << endl;
EnQueue(Q, 'a');
cout << "入队列'a',队列长度为:" << QueueLength(Q) << endl;
EnQueue(Q, 'b');
cout << "入队列'b',队列长度为:" << QueueLength(Q) << endl;
EnQueue(Q, 'c');
cout << "入队列'c',队列长度为:" << QueueLength(Q) << endl;
EnQueue(Q, 'd');
cout << "入队列'd',队列长度为:" << QueueLength(Q) << endl;
if (QueueEmpty(Q))
cout << "队列为空!" << endl;
else
cout << "队列不为空!" << endl;
DeQueueFront(Q, e);
cout << "出队头元素:" << e << ",队列长度为:" << QueueLength(Q) << endl;
DeQueueRear(Q, e);
cout << "出队头元素:" << e << ",队列长度为:" << QueueLength(Q) << endl;
DeQueueFront(Q, e);
cout << "出队头元素:" << e << ",队列长度为:" << QueueLength(Q) << endl;
DeQueueRear(Q, e);
cout << "出队头元素:" << e << ",队列长度为:" << QueueLength(Q) << endl;
if (QueueEmpty(Q))
cout << "队列为空!" << endl;
else
cout << "队列不为空!" << endl;
DestroyQueue(Q);
cout << "----------是否是中心对称序列测试----------" << endl;
char str[maxqsize + 1];
cout << "请输入待检测的字符串(@做间隔,#做结尾):";
cin >> str;
if (CenterMatch(str))
cout << "待检测序列是中心对称序列!" << endl;
else
cout << "待检测序列不是中心对称序列!" << endl;
cout << "请输入待检测的字符串(@做间隔,#做结尾):";
cin >> str;
if (CenterMatch(str))
cout << "待检测序列是中心对称序列!" << endl;
else
cout << "待检测序列不是中心对称序列!" << endl;
return 0;
}
3.7 中心对称序列检验的队列应用示意图
下面示意图展示了队列在中心对称序列检验中的工作过程。
在中心对称检验中,以字符串 a+b@b+a# 为例,程序先将 结束标志 ‘#’ 之前的字符依次压入队列中,然后通过头指针和尾指针指向的队头和队尾元素出队进行比较,。若每个字符都相等,且最后队列为空,则说明该字符串是一个中心对称序列。

4 实验结果
4.1 项目目录结构
项目在zzu_DataStructure_Experiment目录下的exp04文件夹。对应的文件结构为:
exp04/
├── sqQueue.cpp --> 队列基本操作和应用实现和测试文件
└── readme_exp04.md --> exp04项目运行操作和结果记录文件
4.2 实验运行配置和结果截图
这里是单个cpp文件,因此没有编写额外的cmake配置,只需要单独运行单个文件:
以下命令适用于已经配置好c/c++编译的Mac系统。其他平台用户建议直接使用IDE(如Devc++、Vscode等)运行按钮运行。
1️⃣ 打开终端,切换到项目目录,使用mac自带c++编译工具clang++编译:
cd Path/To/exp04
clang++ -std=c++17 sqQueue.cpp -o sqQueue
2️⃣ 运行编译好的可执行程序sqQueue:
./sqQueue
若程序正确运行,得到以下实验结果:

5 报告总结
算法复杂度分析及优、缺点分析
(1) 循环队列的基本操作中,由于队头指针和队尾指针的加入,循环队列的初始化、入队、出队、获取队列长度、判空、判满等基本操作的时间复杂度均为O(1)。利用静态数组增设队头、队尾指针模拟的循环队列,其大小固定不能更改,但是逻辑上简单易懂。
(2) 在用队列实现堆字符串序列的中心对称检验过程中,就是对队列中的元素遍历并进行比较的过程,因此该算法的时间复杂度为O(n)。该算法在使用过程中,用到了出队尾元素这一操作,因此该算法对队列的数据结构有一定的限制。
写在最后
1️⃣ 创作不易,如果你觉得这篇文章对你有用,请点赞收藏关注~。同时如果你认为文章配套开源项目zzu_DataStructure_Experiment对你有用,请留下一个 ⭐️ Star来支持作者,不胜感激~
2️⃣ 转载请注明出处~
1万+

被折叠的 条评论
为什么被折叠?



