实验2
实验报告
( 2025~ 2026学年春季学期)
课程代码 B070730608002
课程名称 数据结构 专业班级 25虚拟1班 学生学号 253051601132 学生姓名 战忠沅 指导教师 曹梅春
信息工程学院
2026年4月21日
实验(训)项目名称 | 栈和队列的应用 | ||||
实验(训)地点 | 明远楼C110 | 实验(训)日期 | 4.21 | ||
小组成员 | 无 | ||||
小组成员 分工情况 | 个人 | ||||
实验(训)所用设备、材料、软件等: Win10操作系统计算机 VC++ 2010学习版软件 | |||||
实验(训)目的: 掌握栈和队列的类型定义方法;掌握栈和队列的基本操作;掌握栈和队列的应用场合,能够根据具体问题选择合适的数据结构。 | |||||
实验(训)内容、步骤、结果、心得体会: 一、实验内容 1.输入一个表达式,表达式中包括三种括号“()”、“[]”和“{}”,判断该表达式的括号是否匹配。检验算法借助一个栈,每当读入一个左括号,则直接入栈,等待相匹配的同类右括号;每当读入一个右括号,若与当前栈顶的左括号类型相同,则二者匹配,将栈顶的左括号出栈,直到表达式扫描完毕。。 2.循环队列的应用——舞伴配对问题:在舞会上,男、女各自排成一队。舞会开始时,依次从男队和女队的队头各出一人配成舞伴。如果两队初始人数不等,则较长的那一队中未配对者等待下一轮舞曲。假设初始男、女人数及性别已经固定,舞会的轮数从键盘输入。试模拟解决上述舞伴配对问题。要求:从屏幕输出每一轮舞伴配对名单,如果在该轮有未配对的,能够从屏幕显示下一轮第一个出场的未配对者的姓名。 二、实验步骤 实验1: #include <iostream> using namespace std; #define MAXSIZE 100 // 栈的最大容量 // ========== 顺序栈的定义 ========== typedef struct { char data[MAXSIZE]; // 存储栈元素的数组 int top; // 栈顶指针,-1表示空栈 } SqStack; // 初始化栈 void InitStack(SqStack &S) { S.top = -1; } // 入栈 bool Push(SqStack &S, char e) { if (S.top == MAXSIZE - 1) { // 栈满 cout << "栈满,无法入栈!" << endl; return false; } S.data[++S.top] = e; // 栈顶指针先+1,再存入元素 return true; } // 出栈 bool Pop(SqStack &S, char &e) { if (S.top == -1) { // 栈空 return false; } e = S.data[S.top--]; // 先取出栈顶元素,指针再-1 return true; } // 取栈顶元素(不出栈) bool GetTop(SqStack S, char &e) { if (S.top == -1) { return false; } e = S.data[S.top]; return true; } // 判断栈是否为空 bool StackEmpty(SqStack S) { return S.top == -1; } // 判断左右括号是否匹配 bool Match(char left, char right) { if (left == '(' && right == ')') return true; if (left == '[' && right == ']') return true; if (left == '{' && right == '}') return true; return false; } // ========== 主函数 ========== int main() { SqStack S; InitStack(S); char str[200]; cout << "请输入表达式: "; cin.getline(str, 200); int i = 0; bool flag = true; char ch; // 当前扫描的字符 char topElem; // 栈顶元素 while (str[i] != '\0') { ch = str[i]; // 遇到左括号,入栈 if (ch == '(' || ch == '[' || ch == '{') { Push(S, ch); } // 遇到右括号,检查栈顶 else if (ch == ')' || ch == ']' || ch == '}') { if (StackEmpty(S)) { cout << "错误:右括号 '" << ch << "' 没有对应的左括号!" << endl; flag = false; break; } GetTop(S, topElem); if (Match(topElem, ch)) { Pop(S, topElem); // 匹配成功,栈顶左括号出栈 } else { cout << "错误:括号类型不匹配!栈顶是 '" << topElem << "',当前是 '" << ch << "'" << endl; flag = false; break; } } // 其他字符直接忽略 i++; } // 表达式扫描完毕,检查栈是否为空 if (flag) { if (!StackEmpty(S)) { cout << "错误:存在未匹配的左括号,剩余 " << (S.top + 1) << " 个!" << endl; flag = false; } } if (flag) { cout << "结果:括号匹配正确!" << endl; } else { cout << "结果:括号不匹配!" << endl; } return 0; } 结果: 实验2: #include <iostream> #include <string> using namespace std; #define MAXSIZE 100 // ========== 循环队列 ========== typedef struct { string data[MAXSIZE]; int front; int rear; int size; } CirQueue; void InitQueue(CirQueue &Q) { Q.front = 0; Q.rear = 0; Q.size = 0; } bool EnQueue(CirQueue &Q, string e) { if (Q.size == MAXSIZE) return false; Q.data[Q.rear] = e; Q.rear = (Q.rear + 1) % MAXSIZE; Q.size++; return true; } bool DeQueue(CirQueue &Q, string &e) { if (Q.size == 0) return false; e = Q.data[Q.front]; Q.front = (Q.front + 1) % MAXSIZE; Q.size--; return true; } bool GetFront(CirQueue Q, string &e) { if (Q.size == 0) return false; e = Q.data[Q.front]; return true; } bool QueueEmpty(CirQueue Q) { return Q.size == 0; } int QueueLength(CirQueue Q) { return Q.size; } // 求最小值 int Min(int a, int b) { return a < b ? a : b; } // ========== 主函数 ========== int main() { CirQueue maleQ, femaleQ; InitQueue(maleQ); InitQueue(femaleQ); int m, n, rounds; string name; // 输入男队 cout << "请输入男队员人数: "; cin >> m; cin.ignore(); cout << "请依次输入男队员姓名:" << endl; for (int i = 0; i < m; i++) { cout << " 第 " << i + 1 << " 位: "; getline(cin, name); EnQueue(maleQ, name); } // 输入女队 cout << "\n请输入女队员人数: "; cin >> n; cin.ignore(); cout << "请依次输入女队员姓名:" << endl; for (int i = 0; i < n; i++) { cout << " 第 " << i + 1 << " 位: "; getline(cin, name); EnQueue(femaleQ, name); } cout << "\n请输入舞会轮数: "; cin >> rounds; cout << "\n========== 舞会开始 ==========\n" << endl; for (int r = 1; r <= rounds; r++) { cout << "--- 第 " << r << " 轮舞曲 ---" << endl; // 核心修正:一轮的配对次数 = 两队当前长度的较小值 int pairNum = Min(QueueLength(maleQ), QueueLength(femaleQ)); int pairCount = 0; string male, female; for (int i = 0; i < pairNum; i++) { DeQueue(maleQ, male); DeQueue(femaleQ, female); cout << " 配对: " << male << " <-> " << female << endl; pairCount++; // 配对后回到队尾,等待下一轮 EnQueue(maleQ, male); EnQueue(femaleQ, female); } cout << " 本轮共配对 " << pairCount << " 对" << endl; // 判断未配对情况 if (QueueLength(maleQ) > QueueLength(femaleQ)) { string nextMale; GetFront(maleQ, nextMale); cout << " >> 女队已空,男队剩余 " << (QueueLength(maleQ) - QueueLength(femaleQ)) << " 人未配对" << endl; cout << " >> 下一轮第一个出场的未配对男队员: " << nextMale << endl; } else if (QueueLength(femaleQ) > QueueLength(maleQ)) { string nextFemale; GetFront(femaleQ, nextFemale); cout << " >> 男队已空,女队剩余 " << (QueueLength(femaleQ) - QueueLength(maleQ)) << " 人未配对" << endl; cout << " >> 下一轮第一个出场的未配对女队员: " << nextFemale << endl; } else { cout << " >> 两队人数相等,全部配对,无剩余人员" << endl; } cout << endl; } cout << "========== 舞会结束 ==========" << endl; return 0; } 结果: 心得体会: 本次实验围绕栈和队列这两种基本数据结构展开,通过"括号匹配"和"舞伴配对"两个具体问题的编程实现,我对线性结构的特性与应用有了更深刻的认识。 在实验一中,我采用顺序栈实现括号匹配。通过手动定义栈的结构体、编写入栈和出栈操作,我真正理解了"后进先出"原则的实际意义。当遇到左括号时入栈,遇到右括号时与栈顶元素匹配,这一过程中栈顶指针的动态变化让我体会到栈在解决"嵌套"和"对称"类问题时的天然优势。 实验二使用循环队列模拟舞伴配对,这是本次实验收获最大的一部分。最初我使用while循环配合"出队配对后回队尾"的逻辑,结果导致程序陷入无限循环。经过分析,我发现问题的根源在于没有明确界定"一轮舞曲"的边界——配对后回队虽然符合循环队列的等待机制,但一轮内的配对次数应由该轮开始时两队人数的较小值决定。修正为for循环控制配对次数后,程序逻辑才正确。这让我深刻认识到,选择合适的数据结构只是第一步,更重要的是将实际问题准确抽象为算法步骤,尤其要注意边界条件的设定。 通过亲手实现相关算法而非直接调用,让我更加理解了顺序栈和循环队列的底层存储原理,包括指针移动、取模运算、队空队满的判断等细节。这次实验让我体会到,数据结构不仅是理论的堆砌,更是解决实际问题的工具,只有将逻辑想清楚、把边界理明白,才能写出正确可靠的程序。 | |||||
教师评语: | |||||
成绩评定 | 教师签名 | ||||