C/C++数据结构课程设计[2023-05-31]
数据结构课程设计
实验(训)指导书
所在学院:计算机科学与工程学院
编写说明
一.实验总体目标
《数据结构》是一门实践性较强的课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。本实验的目标是,学生能正确理解和熟练掌握常用数据结构和算法设计所需的技术,设计中要求综合运用在《数据结构》课程中所学知识,上机解决一些与实际应用结合紧密的、规模较大的问题,通过分析、设计、编码、调试等各环节的训练,使学生深刻理解、牢固掌握数据结构和算法设计技术,掌握分析、解决实际问题的能力。
二、实验(训)总体要求
1.做好实训前的准备以提高上机效率:
提前了解所要做的系统整体结构设计,做到心中有明确的目的要求和任务,要有备而来,应该自己独立的思考和设计你的算法和程序,并争取在规定的时间内如期完成上机工作任务。对于个别目前基础较差的同学,实在是没法完成任务的建议你先参考其他同学的算法,勤学好问,最终自己独立完成,以增强你的感性认识,强化你的实践基础,提高你的实践能力。
⒉ 上机时输入和调试自己所编写的程序时,需要用注重编码规范,如注释、变量名的命名等。对“出错信息”,应善于自己分析判断,并充分利用开发工具提供的错误信息和调试手段解决出现的问题,及时修改与完善算法、源程序,随时记录有价值的内容。解决问题是学习调式程序的良好机会。切不可不编程序或抄别人的程序去上机,应从养成严谨的科学作风。
⒊ 程序调试通过后,应运行程序并根据事先准备的典型数据验证结果,在运行时要注意在输入不同数据时所得到的不同结果。
三、适用专业及先修课程
适用专业:软件工程、物联网工程、网络工程专业、数据科学与大数据技术、区块链。
先修课程:程序设计基础。
四.实验(训)总学时
实验(训)总学时为24学时。
每个选题的课时分配如下表:
序号 设计模块 学时
1 需求分析 4
2 总体设计 4
3 详细设计 6
4 编码实现 8
5 调试与测试 2
合计 24
五.实验(训)环境
每人一台计算机,安装Dev C++。
目 录
实验(训)项目一 学生成绩管理 1
一、实验(训)目的 1
二、实验(训)仪器及设备 1
三、实训(训)内容 1
四、实验(训)步骤及要求 1
五、实验(训)报告要求 8
实验(训)项目二 停车场管理 9
一、实验(训)目的 9
二、实验(训)仪器及设备 9
三、实验(训)内容 9
四、实验(训)步骤及要求 9
五、实验(训)报告要求 15
实验(训)项目三 家谱管理 16
一、实验(训)目的 16
二、实验(训)仪器及设备 16
三、实验(训)内容 16
四、实验(训)步骤及要求 16
五、实验(训)报告要求 24
实验(训)项目四:公交线路管理 25
一、实验(训)目的 25
二、实验(训)仪器及设备 25
三、实验(训)内容 25
四、实验(训)步骤及要求 25
五、实验(训)报告要求 37
其他选题 38
1.运动会分数统计 38
2.飞机订票系统 38
3.文章编辑 39
4.宿舍管理查询软件 39
5.校园导航问题 40
6.教学计划编制问题 40
7.散列法的实验研究 40
8.图书借阅管理系统 40
9.学生成绩管理 40
10.活期储蓄帐目管理 41
11.二叉排序树的实现 41
12.最小生成树问题 41
13.通讯录的制作 41
14.哈夫曼编码/译码器 42
15.图书管理系统 42
16.散列表的设计与实现 43
17.顺序结构、动态链表结构下的一元多项式的加法、减法、乘法的实现。 44
18.利用栈求表达式的值,可供小学生作业,并能给出分数。 44
19.简易文本编辑器 44
20.二叉树的中序、前序、后序的递归、非递归遍历算法,层次序的非递归遍历算法的实现,应包含建树的实现。 44
21.学生搭配问题 45
22.猴子吃桃子问题 45
23.数制转换问题 45
24.排序综合 46
25.学生成绩管理系统 46
26.图的遍历的实现 47
27.线索二叉树的应用 47
28.稀疏矩阵应用 47
29.树的应用 47
30. 文本文件单词的检索与计数 47
31.任意长的整数加法 48
32. 二叉平衡排序树 48
33.串的查找和替换 48
34.约瑟夫环 49
35.构造可以使n个城市连接的最小生成树 49
36.客户消费积分管理系统 49
37.产品进销存管理系统 49
38. 特殊矩阵的压缩存储算法的实现 50
39.算术表达式的求解 50
40.实时监控报警系统 50
41. 车厢调度 50
42.迷宫问题(栈) 50
43.迷宫问题(队列)(同上) 51
44二叉搜索树:各种搜索树效率比较 51
45. 病毒测试程序 52
46关键路径问题 52
47.神秘国度的爱情故事 52
48.并查集:检查网络 53
49.广义表的应用 53
50.网络流:宇宙旅行 54
实验(训)项目一 学生成绩管理
一、实验(训)目的
通过课程设计提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。具体包括:
1、了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
2、初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
3、提高综合运用所学线性结构的理论知识和方法独立分析和解决问题的能力;
4、学习使用线性结构来解决实际问题。
二、实验(训)仪器及设备
PC电脑一台,Dev C++
三、实训(训)内容
学生成绩管理是学校教务部门日常工作的重要组成部分,其处理信息量很大。本项目是对学生成绩管理的简单模拟,用菜单选择方式完成下列功能:输入学生数据;输出学生数据;学生数据查询;添加学生数据;修改学生数据;删除学生数据。
四、实验(训)步骤及要求
本项目的数据是一组学生的成绩信息,每条学生的成绩信息由学号、姓名和成绩组成,这组学生的成绩信息具有相同特性,属于同一数据对象,相邻数据元素之间存在序偶关系。由此可以看出,这些数据具有线性表中数据元素的性质,所以该系统的数据采用线性表来存储。
顺序表是线性表的顺序存储结构,是指用一组连续的内存单元依次存放线性表的数据元素。在顺序存储结构下,逻辑关系相邻的两个元素在物理位置上也相邻,这是顺序表的特点。本项目可以采用顺序表的线性表顺序存储结构。
若一个数据元素仅占一个存储单元,第i个数据元素的地址为
Loc(ai)=loc(a1)+(i-1)
假设线性表中每个元素占用k个存储单元,那么在顺序表中,线性表的第i个元素的存储位置与第1个元素的存储位置的关系是
Loc(ai)=loc(a1)+(i-1)*k
这里Loc(ai)是第i个元素的存储位置,loc(a1)是第1个元素的存储位置,也称为线性表的基址。显然,顺序表便于进行随机访问,故线性表的顺序存储结构是一种随机存储结构。
顺序表适宜于做查找这样的静态操作;顺序存储的优点是存储密度大,存储空间利用率高。缺点是插入或删除元素时不方便。
由于C语言的数组类型也有随机存储的特点,一维数组的机内表示就是顺序结构。因此,可用C语言的一维数组实现线性表的顺序存储。数组实现线性表的顺序存储的优点是可以随机存取表中任一元素O(1),存储空间使用紧凑;缺点是在插入,删除某一元素时,需要移动大量元素O(n),预先分配空间需按最大空间分配,利用不充分,表容量难以扩充。
用结构体类型定义每个学生数据,故该数组中的每个数据的结构可描述为:
typedef struct STU
{ char stuno[10]; //学号char name[10]; //姓名float score; //成绩
} ElemType;
参考程序清单如下:
#include<iostream.h>
#include<iomanip.h>
#include<malloc.h>
#include<string.h>
#define MaxListSize 20
#define EQUAL 1
typedef struct STU{char stuno [10];char name [10];float score;
}ElemType;
class List
{private://线性表的数组表示ElemType elem[MaxListSize];int length;int MaxSize;public: //输入学生数据void init(List **L,int ms);//删除所有学生数据void DestroyList(List &L){free(&L);}//将顺序表置为空表void ClearList(){length=0;}//判断顺序表是否为空表bool ListEmpty(){return length==0;}//判断顺序表是否为满bool ListFull(){return length==MaxSize;}//删除某个学生数据bool ListDelete(int,ElemType &e);//遍历顺序表void ListTraverse();//返回顺序表的长度int ListLength();//学生数据查询void GetElem(int,ElemType *);//修改学生数据bool UpdateList(ElemType& e,ElemType);//添加学生数据bool ListInsert(int,ElemType &);//对学生数据按升序或降序输出void printlist(int);
};void List::init(List **L,int ms)
{*L=(List *)malloc(sizeof(List));(*L)->length=0;(*L)->MaxSize=ms;
}
int List::ListLength()
{return length;}bool List::ListDelete(int mark,ElemType &e)
{int i,j;if(ListEmpty()) return false;if(mark>0) { //删除表头元素e=elem[0];for(i=1; i<length; i++)elem[i-1]=elem[i];}else //删除表尾元素if(mark<0) e=elem[length-1];else { //删除值为e的元素for(i=0;i<length;i++)if(strcmp(elem[i].name,e.name)==0) break;if(i>=length) return false;else e=elem[i];for(j=i+1;j<length;j++)elem[j-1]=elem[j];}length--;return true;
}
void List::ListTraverse()
{for(int i=0;i<length;i++){cout<<setw(8)<<elem[i].name;cout<<setw(10)<<elem[i].stuno;cout<<setw(9)<<elem[i].age;cout<<setw(8)<<elem[i].score<<endl;}
}
void List::GetElem(int i,ElemType *e)
{*e=elem[i];}bool List::EqualList(ElemType *e1,ElemType *e2)
{ if (strcmp(e1->name,e2->name))return false;if (strcmp(e1->stuno,e2->stuno))return false;if (e1->age!=e2->age)return false;if (e1->score!=e2->score)return false;return true;
}
bool List::Less_EqualList(ElemType *e1,ElemType *e2)
{ if(strcmp(e1->name,e2->name)<=0) return true;else return false;
}
bool List::LocateElem(ElemType e,int type)
{ int i;switch (type){ case EQUAL:for(i=0;i<length;i++)if(EqualList(&elem[i],&e))return true;break;default:break;}return false;
}
//修改学生数据
bool List::UpdateList(ElemType& e,ElemType e1)
{for(int i=0;i<length;i++)if(strcmp(elem[i].name,e.name)==0) {elem[i]=e1;return true;}return false;
}
bool List::ListInsert(int i,ElemType &e)
{ElemType *p,*q;if(i<1||i>length+1) return false;q=&elem[i-1];for(p=&elem[length-1];p>=q;--p)*(p+1)=*p;*q=e;++length;return true;
}
//对学生成绩按升序或降序输出
void List::printlist(int mark)
{int* b=new int[length];int i,k;cout<<" 姓名 学号 成绩\n";if(mark!=0){for(i=0; i<length;i++) b[i]=i;for(i=0; i<length;i++) {k=i;for(int j=i+1;j<length;j++) {if(mark==1&&elem[b[j]].score<elem[b[k]].score) k=j;if(mark==-1&&elem[b[k]].score<elem[b[j]].score) k=j;}if(k!=i) {int x=b[i];b[i]=b[k];b[k]=x;}}for(int i=0;i<length;i++){cout<<setw(8)<<elem[b[i]].name;cout<<setw(10)<<elem[b[i]].stuno;cout<<setw(9)<<elem[b[i]].age;cout<<setw(8)<<elem[b[i]].score<<endl;}}else {for(i=0;i<length;i++){cout<<setw(8)<<elem[i].name;cout<<setw(10)<<elem[i].stuno;cout<<setw(9)<<elem[i].age;cout<<setw(8)<<elem[i].score<<endl;}}
}void main()
{ cout<<"linelist1m.cpp运行结果:\n";ElemType e,e1,e2,e3,e4,e5,e6;List *La,*Lb,*Lc;int k;cout<<"首先调用插入函数.\n";La->init(&La,4);strcpy(e1.name,"stu1");strcpy(e1.stuno,"100001");e1.age=22;e1.score=88;La->ListInsert(1,e1);strcpy(e2.name,"stu2");strcpy(e2.stuno,"100002");e2.age=21;e2.score=79;La->ListInsert(2,e2);strcpy(e3.name,"stu3");strcpy(e3.stuno,"100003");e3.age=19;e3.score=87;La->ListInsert(3,e3);La->printlist(0);cout<<"表La长:"<<La->ListLength()<<endl;cin.get();Lb->init(&Lb,4);strcpy(e4.name,"zmofun");strcpy(e4.stuno,"100001");e4.age=20;e4.score=94;Lb->ListInsert(1,e4);strcpy(e5.name,"bobjin");strcpy(e5.stuno,"100002");e5.age=23;e5.score=69;Lb->ListInsert(2,e5);strcpy(e6.name,"stu1");strcpy(e6.stuno,"100001");e6.age=22;e6.score=88;Lb->ListInsert(3,e6);Lb->printlist(0);cout<<"表Lb长:"<<Lb->ListLength()<<endl;cin.get();k=Lc->ListDelete(-1,e6);if(k==0) cout<<"删除失败!\n";else cout<<"删除成功!\n";cout<<"输出表Lc:\n";Lc->printlist(0);cin.get();cout<<"按成绩升序输出表Lc\n";Lc->printlist(1);cin.get();cout<<"按成绩降序输出表Lc\n";Lc->printlist(-1);cin.get();
}
五、实验(训)报告要求
(1)按要求撰写实训报告,记录实验内容、实验操作方法与步骤。
(2)记录实验步骤的时候,可以只记录核心源代码。
(3)请记录实训结果及自己对结果的分析。
(4)请记录实训过程中遇到的问题以及解决方法,并可加上自己对实训的改进意见。
实验(训)项目二 停车场管理
一、实验(训)目的
通过课程设计提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。具体包括:
1、了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
2、初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
3、提高综合运用所学栈的理论知识和方法独立分析和解决问题的能力;
4、学习使用栈来解决实际问题。
二、实验(训)仪器及设备
每人一台计算机,配置较高,安装dev c++。
三、实验(训)内容
设停车场是一个可以停放n辆汽车的南北方向的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端),若车场内已停满n辆车,那么后来的车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。试为停车场编制按上述要求进行管理的模拟程序。要求程序输出每辆车到达后的停车位置(停车场或便道上),以及某辆车离开停车场时应缴纳的费用和它在停车场内停留的时间。
停车场的管理流程如下:
①当车辆要进入停车场时,检查停车场是否已满,如果未满则车辆进入停车场;如果停车场已满,则车辆进入便道等候。
②当车辆要求出栈时,先让在它之后进入停车场的车辆退出停车场为它让路,再让该车退出停车场,让路的所有车辆再按其原来进入停车场的次序进入停车场。之后,再检查在便道上是否有车等候,有车则让最先等待的那辆车进入停车场。
四、实验(训)步骤及要求
由于停车场只有一个大门,当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,先进停车场的后退出,后进车场的先退出,符合栈的“后进先出,先进后出”的操作特点,因此,可以用一个栈来模拟停车场。而当停车场满后,继续来到的其它车辆只能停在便道上,根据便道停车的特点,先排队的车辆先离开便道进入停车场,符合队列的“先进先出,后进后出”的操作特点,因此,可以用一个队列来模拟便道。排在停车场中间的车辆可以提出离开停车场,并且停车场内在要离开的车辆之后到达的车辆都必须先离开停车场为它让路,然后这些车辆依原来到达停车场的次序进入停车场,因此在前面已设的一个栈和一个队列的基础上,还需要有一个地方保存为了让路离开停车场的车辆,由于先退出停车场的后进入停车场,所以很显然保存让路车辆的场地也应该用一个栈来模拟。因此,本题求解过程中需用到两个栈和一个队列。栈以顺序结构实现,队列以链表结构实现。
程序清单如下:
程序提示:以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码以及到达或离去的时刻。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车辆离去,则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。
#include<stdio.h>
#include <stdlib.h>
#include<iostream.h>
#include<string.h>
#include<math.h>
#define size 1 //停车场位置数
//模拟停车场的堆栈的性质;
typedef struct zanlind{ int number; //汽车车号int ar_time; //汽车到达时间
}zanInode;
typedef struct{zanInode *base; //停车场的堆栈底zanInode *top; //停车场的堆栈顶int stacksize_curren;
}stackhead;
//堆栈的基本操作;
void initstack(stackhead &L) //构造一个空栈
{L.base=(zanInode*)malloc(size*sizeof(zanlind));if(!L.base) exit(0);L.top=L.base;L.stacksize_curren=0;
}
void push(stackhead &L,zanInode e) //把元素e压入s栈
{*L.top++=e;L.stacksize_curren++;
}
void pop(stackhead &L,zanInode &e) //把元素e弹出s栈
{if(L.top==L.base) {cout<<"停车场为空 !!";return;}e=*--L.top;L.stacksize_curren--;
}
//模拟便道的队列的性质;
typedef struct duilie{ int number; //汽车车号int ar_time; //汽车到达时间struct duilie *next;
}*queueptr;
typedef struct{queueptr front; //便道的队列的对头queueptr rear; //便道的队列的队尾int length;
}linkqueue;
//队列的基本操作;
void initqueue(linkqueue &q) //构造一个空队列
{q.front=q.rear=(queueptr)malloc(sizeof(duilie));if(!q.front||!q.rear)exit(0);q.front->next=NULL;q.length=0;
}
void enqueue(linkqueue &q,int number,int ar_time) //把元素的插入队列(属性为number,ar_time)
{queueptr p;p=(queueptr)malloc(sizeof(duilie));if(!p) exit(0);p->number=number;p->ar_time=ar_time;p->next=NULL;q.rear->next=p;q.rear=p;q.length++;
}
void popqueue(linkqueue &q,queueptr &w) //把元素的插入队列(属性为number,ar_time)
{queueptr p;if(q.front==q.rear) {cout<<"停车场的通道为空 ! !"<<endl;return;}p=q.front->next;w=p; q.front->next=p->next;q.length--;if(q.rear==p) q.front=q.rear;}
void jinru(stackhead &st,linkqueue &q) //对进入停车场的汽车的处理;
{int number,time_a;cout<<"车牌为:";cin>>number;cout<<"进场的时刻:";cin>>time_a;if(st.stacksize_curren<2){zanInode e;e.number=number;e.ar_time=time_a;push(st,e);cout<< " 该车已进入停车场在: "<<st.stacksize_curren<<" 号车道"<<endl<<endl;}else{enqueue(q,number,time_a);cout<<"停车场已满,该车先停在便道的第"<<q.length<<"个位置上"<<endl;}}void likai(stackhead &st,stackhead &sl,linkqueue &q) //对离开的汽车的处理;
{ //st堆栈为停车场,sl堆栈为倒车场int number,time_d,flag=1,money,arrivaltime; //q为便道队列cout<<"车牌为:";cin>>number;cout<<"出场的时刻:";cin>>time_d;zanInode e,q_to_s;queueptr w;while(flag) //找到要开出的车,并弹出停车场栈{pop(st,e);push(sl,e);if(e.number==number){flag=0;money=(time_d-e.ar_time)*2;arrivaltime=e.ar_time;}}pop(sl,e); //把临时堆栈的第一辆车(要离开的)去掉;while(sl.stacksize_curren) //把倒车场的车倒回停车场{pop(sl,e);push(st,e);}if(st.stacksize_curren<2&&q.length!=0) //停车场有空位,便道上的车开进入停车场{popqueue(q,w);q_to_s.ar_time=time_d;q_to_s.number=w->number;push(st,q_to_s);cout<<"车牌为"<<q_to_s.number<<"的车已从通道进入停车场,所在的停车位为:"<<st.stacksize_curren<<endl<<endl;}cout<<"\n 收 据"<<endl; cout<<" ====================== 车牌号: "<<number<<endl; cout<<"==================================================="<<endl;cout<<"|进车场时刻 | 出车场时刻 | 停留时间 | 应付(元)|"<<endl;cout<<"===================================================="<<endl;cout<<"| "<<arrivaltime<<" | "<<time_d<<" | "<<time_d-arrivaltime<<" | "<<money<<" |"<<endl;cout<<"-----------------------------------------------------"<<endl<<endl;}
void main()
{
int m=100;
char flag; //进入或离开的标识;
stackhead sting,slinshi; //停车场和临时倒车场堆栈的定义;
linkqueue line; //队列的定义;
initstack(sting); //构造停车场堆栈sting
initstack(slinshi); //构造倒车场堆栈slinshi
initqueue(line); //构造便道队列line
while(m)
{cout<<"\n ** 停车场管理程序 **"<<endl;cout<<"==================================================="<<endl;cout<<"** **"<<endl;cout<<"** A --- 汽车 进 车场 D --- 汽车 出 车场 **"<<endl;cout<<"** **"<<endl;cout<<"** E --- 退出 程序 **"<<endl;cout<<"==================================================="<<endl;cout<<" 请选择 :(A,D,E): ";cin>>flag;switch(flag){case 'A': jinru(sting,line);break; //汽车进车场case 'D': likai(sting,slinshi,line);break; //汽车出车场case 'E': exit(0);}m--;
}
}
五、实验(训)报告要求
(1)按要求撰写实训报告,记录实验内容、实验操作方法与步骤。
(2)记录实验步骤的时候,可以只记录核心源代码。
(3)请记录实训结果及自己对结果的分析。
(4)请记录实训过程中遇到的问题以及解决方法,并可加上自己对实训的改进意见。
实验(训)项目三 家谱管理
一、实验(训)目的
通过课程设计提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。具体包括:
1、了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
2、初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
3、提高综合运用所学树型结构的理论知识和方法独立分析和解决问题的能力;
4、学习使用树型结构来解决实际问题。
二、实验(训)仪器及设备
每人一台计算机,配置较高,安装dev c++。
三、实验(训)内容
家谱(或称族谱)是一种以表谱形式,记载一个以血缘关系为主体的家族世系繁衍和重要人物事迹的特殊图书体裁。家谱是中国特有的文化遗产,是中华民族的三大文献(国史,地志,族谱)之一,属珍贵的人文资料,对于历史学、民俗学、人口学、社会学和经济学的深入研究,均有其不可替代的独特功能。本项目对家谱管理进行简单的模拟,以实现查看祖先和子孙个人信息、插入家族成员、删除家族成员等功能。
本项目的实质是完成对家谱成员信息的建立、查找、插入、修改、删除等功能,可以首先定义家族成员的数据结构,然后将每个功能写成一个函数来完成对数据的操作,最后完成主函数以验证各个函数功能并得出运行结果。
四、实验(训)步骤及要求
因为家族中的成员之间存在一个对多个的层次结构关系,所以不能用上面讲的线性表来表示。家谱从形状上看像一颗倒长的树,所以用树结构来表示家谱比较适合。树型结构是一类非常重要的非线性数据结构,直观看来,树是以分支关系定义的层次结构。
可以二叉链表作为树的存储结构,链表中的两个链域分别指向该结点的第一个孩子结点和下一个兄弟结点,固该表示法又称二叉树表示法,或孩子兄弟表示法。孩子兄弟表示法是一种链式存储结构,它通过描述每个结点的一个孩子和兄弟信息来反映结点之间的层次关系,其具体的结点结构为:
firstChild data nextSibling
其中,firstchild为指向该结点第一个孩子的指针,nextsibling为指向该结点下一个兄弟,elem是数据元素内容,举例如下:
其存储形式定义如下:
typedef struct CSLinklist{Elemtype data;struct CSLinklist *firstchild,*nextsibling;
} CSLinklist,*CSTree;
程序清单如下所示:
//树的孩子兄弟表示法为存储结构的结构体Tree.h
template<class T> class Tree;
template<class T> struct TreeNode
{friend class Tree<T>;//树类为友元private:TreeNode<T> *firstChild;//第一个孩子结点指针域TreeNode<T> *nextSibling;//下一个兄弟结点指针域public:T data;//数据域
//构造函数TreeNode(T value,TreeNode<T> *fc=NULL,TreeNode<T> *ns=NULL):data(value),firstChild(fc),nextSibling(ns){}
//访问指针域的成员函数TreeNode<T>* &FirstChild(){return firstChild;}TreeNode<T>* &NextSibling(){return nextSibling;}
};
//树类
template<class T> class Tree
{private:TreeNode<T> *root;//根结点指针TreeNode<T> *curr;//当前结点指针//显示以t为先根结点的树的数据域void PreOrderTree(TreeNode<T> *&t);//显示以t为后根结点的树的数据域void PosOrderTree(TreeNode<T> *&t);//使当前结点为t所指结点int Current(TreeNode<T> *&t);//在树root中回溯查找结点s的双亲结点TreeNode<T> *SearchParent(TreeNode<T> *&root,TreeNode<T> *&s);public://构造函数与析构函数Tree(){root=curr=NULL;}~Tree(){DeleteSubTree(root);}//使根结点为当前结点int Root();//使当前结点的双亲结点为当前结点int Parent();//使当前结点的第一个孩子结点为当前结点int FirstChild();//使当前结点的兄弟结点为当前结点int NextSibling();//把valve插入到当前结点的最后一个结点void InsertChild(T value);//删除以t为根结点的子树void DeleteSubTree(TreeNode<T> *&t);//删除当前结点的第i个孩子结点int DeleteChild(int i);//删除以root为根结点的子树的第i个孩子结点int DeleteChild1(int i);//按先根遍历次序显示树的数据域值void DisplayTree();//按后根遍历次序显示树的数据域值void DisplayTree1();
};//树类的实现Tree.cpp
template<class T>
void Tree<T>::DeleteSubTree(TreeNode<T> *&t)
{if(t==NULL) return;TreeNode<T> *q=t->firstChild,*p;while(q!=NULL){p=q->nextSibling;DeleteSubTree(q);q=p;}printf("释放:%2c",t->data);delete t;
}
template<class T>
int Tree<T>::Current(TreeNode<T> *&t)
{if(t==NULL) return 0;curr=t;return 1;
}
template<class T>
int Tree<T>::Root()
{if(root==NULL){curr=NULL;return 0;}return Current(root);
}
template<class T>
int Tree<T>::FirstChild()
{if(curr!=NULL&&curr->firstChild!=NULL)return Current(curr->firstChild);else return 0;
}
template<class T>
int Tree<T>::NextSibling()
{if(curr!=NULL&&curr->nextSibling!=NULL)return Current(curr->nextSibling);else return 0;
}
template<class T>
int Tree<T>::Parent()
{if(curr==NULL){curr=root;return 0;}TreeNode<T> *p=SearchParent(root,curr);if(p==NULL) return 0;else return Current(p);
}
template<class T>
TreeNode<T> *Tree<T>::SearchParent(TreeNode<T> *&root,TreeNode<T> *&s)
{if(root==NULL) return NULL;if(root->FirstChild()==s||root->NextSibling()==s)return root;TreeNode<T> *p;if((p=SearchParent(root->FirstChild(),s))!=NULL) return p;if((p=SearchParent(root->NextSibling(),s))!=NULL) return p;return NULL;
}
template<class T>
void Tree<T>::InsertChild(T value)
{TreeNode<T> *newNode=new TreeNode<T> (value);if(root==NULL) //当为空树时{root=curr=newNode;return;}if(curr->firstChild==NULL)//当当前结点无孩子时curr->firstChild=newNode;else //当当前结点有孩子时{TreeNode<T> *p=curr->firstChild;while(p->nextSibling!=NULL) p=p->nextSibling;p->nextSibling=newNode;}Current(newNode);//使新建立的结点成为当前结点
}
template<class T>
int Tree<T>::DeleteChild(int i)
{TreeNode<T> *r=NULL;if(i==1) //当删除当前结点的第一棵子树时{r=curr->firstChild;if(r==NULL) return 0;//要删除子树为空时返回curr->firstChild=r->nextSibling;//脱链要删除的子树}else { //当删除当前结点的其他子树时int k=1;TreeNode<T> *p=curr->firstChild;while(p!=NULL&&k<=i-1)//寻找要删除子树的指针{p=p->nextSibling;k++;}if(p!=NULL)//寻找到要删除的子树的指针{r=p->nextSibling;if(r!=NULL)p->nextSibling=r->nextSibling;else return 0;}else return 0;}DeleteSubTree(r);return 1;
}
template<class T>
int Tree<T>::DeleteChild1(int i)
{if(root==NULL) return 0;//当为空树时TreeNode<T> *r=NULL,*q=root->firstChild;if(i==1&&q!=NULL) //当第一结点有孩子时{r=root->firstChild;root->firstChild=r->nextSibling;//脱链要删除的子树}else //要删除第一结点外的其他子树时{int k=1;TreeNode<T> *p=root->firstChild;while(p!=NULL&&k<=i-1)//寻找要删除子树的指针{p=p->nextSibling;k++;}if(p!=NULL) //寻找到要删除的子树的指针{r=p->nextSibling;if(r!=NULL)p->nextSibling=r->nextSibling;//脱链要删除的子树else return 0;}else return 0;}DeleteSubTree(r);//调用函数执行删除return 1;
}
template<class T>
void Tree<T>::PreOrderTree(TreeNode<T> *&t)
{if(t==NULL) return;cout<<setw(2)<<t->data;//显示根结点数据if(t->firstChild!=NULL)//先根遍历子树PreOrderTree(t->firstChild);if(t->nextSibling!=NULL)PreOrderTree(t->nextSibling);
}
template<class T>
void Tree<T>::DisplayTree()
{PreOrderTree(root);}template<class T>
void Tree<T>::DisplayTree1()
{PosOrderTree(root);}template<class T>
void Tree<T>::PosOrderTree(TreeNode<T> *&t)
{if(t==NULL) return;if(t->firstChild!=NULL)//后根遍历子树PosOrderTree(t->firstChild);printf("%2c",t->data);//显示根结点数据if(t->nextSibling!=NULL)PosOrderTree(t->nextSibling);
}
//树类相关操作的测试TreeM.cpp
#include<iostream.h>
#include<iomanip.h>
#include<stdlib.h>
#include<conio.h>
#include<stdio.h>
#include "Tree.h"
#include "Tree.cpp"
void main()
{printf("TreeM.cpp运行结果:\n");int i;Tree<char> t;t.InsertChild('A');for(i=0;i<7;i++){t.Root();if(i>=3&&i<5) t.FirstChild();t.InsertChild('B'+i);}printf("按后根遍历显示的结点次序为:\n");t.DisplayTree1();int k;printf("\n输入欲删除第几个结点(k):");scanf("%d",&k);if(t.DeleteChild1(k))printf("\n第%d个孩子结点,删除成功!\n",k);else printf("第%d个孩子结点,删除失败!\n",k);printf("按先根遍历显示的结点次序为:\n");t.DisplayTree();cin.get();printf("\n析构函数按后根遍历释放结点的次序为:\n");cin.get();
}
五、实验(训)报告要求
(1)按要求撰写实训报告,记录实验内容、实验操作方法与步骤。
(2)记录实验步骤的时候,可以只记录核心源代码。
(3)请记录实训结果及自己对结果的分析。
(4)请记录实训过程中遇到的问题以及解决方法,并可加上自己对实训的改进意见。
实验(训)项目四:公交线路管理
一、实验(训)目的
通过课程设计提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。具体包括:
1、了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
2、初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
3、提高综合运用所学图型结构的理论知识和方法独立分析和解决问题的能力;
4、学习使用图型结构来解决实际问题。
二、实验(训)仪器及设备
每人一台计算机,配置较高,安装dev c++。
三、实验(训)内容
本项目是对公交车线路信息的简单模拟,以完成建立公交路线信息、修改公交路线信息和删除公交路线信息等功能。
本项目的实质是完成对公交线路信息的建立、查找、插入、修改、删除等功能,可以首先定义项目的数据结构,然后将每个功能写成一个函数来完成对数据的操作,最后完成主函数以验证各个函数功能并得出运行结果。
四、实验(训)步骤及要求
公交站点之间的关系可以是任意的,任意两个站点之间都可能相关。而在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。所以可以用图形结构来表示n个公交站点之间以及站点之间可能设置的公交路线,其中网的顶点表示公交站点,边表示两个站点之间的路线,赋予边的权值表示相应的距离。
因为公交路线是有一定的连续关系的,如果想输出从某一个起始点开始到某一终点结束的公交路线,就需要找到从某一顶点开始的第一个邻接点和下一个邻接点。因为在邻接表中容易找到任一顶点的第一个邻接点和下一个邻接点,所以本项目使用了图的邻接表存储结构。邻接表是图的一种链式存储结构。在邻接表中,对图的每一个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点vi的边(对有向图是以顶点vi为尾的弧)。每个结点由三个域组成,其中邻接点域(adjvex)指示与顶点vi邻接的点在图中的位置,链域(nextarc)指示下一条边或弧的结点;数据域(info)存储和边或弧相关的信息,如权值等。每个链表上附设一个表头结点,在表头结点中,除了设有链域(firstarc)指向链表中第一个结点之外,还设有存储顶点vi的名或其它有关信息的数据域(data)。这些表头结点通常以顺序结构的形式存储,以便随机访问任意顶点的链表。图的邻接表存储表示结构可形式的说明如下:
#define MAX_VERTEX_NUM 20
typedef struct ArcNode{ //弧的结构
int adjvex; //该弧所指向的顶点的位置
struct ArcNode *nextarc; //指向下一条弧的指针
InfoType *info; //该弧相关信息的指针
}ArcNode;
typedef struct VNode{ //顶点结构
VertexType data; //顶点信息
ArcNode *firstarc; //指向第一条依附该顶点的弧的指针
}VNode, AdjList[MAX_VERTEX_NUM];
typedef struct { //图的结构
AdjList vertices;
int vexnum, arcnum; //图的当前顶点数和弧数
int kind; //图的种类标志
}ALGraph;
程序清单如下:
//图的相关数据类型的定义graph1.h
//最多顶点数
const int MaxV=10;
//定义邻接表中的边结点类型
struct edgenode {int adjvex; //邻接点域int weight; //权值域edgenode* next; //指向下一个边结点的链域edgenode(){}edgenode(int d,int w):adjvex(d),weight(w),next(NULL){}
};
struct Top //顶点数组的元素类型
{char data;//顶点数据edgenode *adj;//邻接表指针
};
struct RCW
{int row;int col;int weight;
};
//邻接表的类定义
class AdjAdjoin
{private:Top g[MaxV];//顶点数组int size; //顶点个数int numE; //当前边的条数public:edgenode **GL;//定义邻接表//构造函数AdjAdjoin() {}//构造函数,初始化图的邻接表AdjAdjoin(edgenode **gl,int n);//判断图空否bool GraphEmpty() {return size==0;}//取当前顶点数int NumV() {return size;}//取当前边数int NumEdges() {return numE;}//取顶点i的值char GetValue(const int i);//取弧<v1,v2>的权int GetWeight(const int v1,const int v2);//在位置pos处插入顶点Vvoid InsertV(const char &V);//插入弧<v1,v2>,权为weightvoid InsertEdge(const int v1,const int v2,int weight);//删除顶点i与顶点i相关的所有边void DeleteVE(const int v);//删除弧<v1,v2>void DeleteEdge(const int v1,const int v2);//删除图的邻接表void DeleteAdjoin(int n);//建立图void CreatGraph(char V[],int n,RCW E[],int e);//建立图的邻接表void CreateAdjoin(int n,int k1,int k2,RCW rcw[]);//从初始点vi出发深度优先搜索由邻接表GL表示的图void dfsAdjoin(bool*& visited,int i,int n);//从初始点vi出发广度优先搜索由邻接表GL表示的图void bfsAdjoin(bool*& visited,int i,int n);//检查输入的边序号是否越界,若越界则重输void Check(int n,int& i,int& j);//对非连通图进行深度优先搜索void dfsAdjoin(int n);//对非连通图进行广度优先搜索void bfsAdjoin(int n);
};//图的相关运算的实现graph1.cpp
#include"graph1.h"
//构造函数,初始化图的邻接表
AdjAdjoin::AdjAdjoin(edgenode **gL,int n)
{GL=gL;for(int i=0;i<n;i++){g[i].adj=GL[i]=NULL;}size=numE=0;
}
//建立图的邻接表
void AdjAdjoin::CreateAdjoin(int n,int k1,int k2,RCW rcw[])
{int i,j,k,e,w;cout<<"输入图的总边数:";cin>>e;if(k1==0 && k2==0) { //建立无向无权图cout<<"输入"<<e<<"条无向无权边的起点和终点序号!"<<endl;for(k=1; k<=e; k++) {cin>>i>>j;Check(n,i,j);//向序号i的单链表的表头插入一个边结点edgenode *p=new edgenode;p->adjvex=j; p->weight=1;p->next=GL[i];GL[i]=p;//向序号j的单链表的表头插入一个边结点p=new edgenode;p->adjvex=i; p->weight=1;cout<<'('<<p->adjvex<<','<<j<<','<<p->weight<<")\n";p->next=GL[j];GL[j]=p;}}else if(k1==0 && k2!=0) { //建立无向有权图cout<<"输入"<<e<<"条无向带权边的起点和终点序号及权值!"<<endl;for(k=0; k<e; k++) {i=rcw[k].row;j=rcw[k].col;w=rcw[k].weight;//cin>>i>>j>>w;Check(n,i,j);//向序号i的单链表的表头插入一个边结点edgenode *p=new edgenode;p->adjvex=j; p->weight=w;p->next=GL[i];GL[i]=p;//向序号j的单链表的表头插入一个边结点p=new edgenode;p->adjvex=i;p->weight=w;p->next=GL[j];GL[j]=p;}}else if(k1!=0&&k2==0) { //建立有向无权图cout<<"输入"<<e<<"条有向无权边的起点和终点序号!"<<endl;for(k=1; k<=e; k++) {cin>>i>>j;Check(n,i,j);//向序号i的单链表的表头插入一个边结点edgenode* p=new edgenode;p->adjvex=j; p->weight=1;p->next=GL[i];GL[i]=p;}}else if(k1!=0&&k2!=0) { //建立有向有权图cout<<"输入"<<e<<"条有向有权边的起点和终点序号及权值!"<<endl;for(k=1; k<=e; k++) {cin>>i>>j>>w;Check(n,i,j);edgenode* p=new edgenode;p->adjvex=j; p->weight=w;p->next=GL[i];GL[i]=p;}}numE=e;size=n;
}
//从初始点vi出发深度优先搜索由邻接表GL表示的图
void AdjAdjoin::dfsAdjoin(bool*& visited,int i,int n)
{cout<<g[i].data<<':'<<i<<" ";visited[i]=true;//取vi邻接表的表头指针edgenode *p=GL[i];//依次搜索vi的每个邻接点while (p!=NULL) {int j=p->adjvex;//j为vi的一个邻接点序号if(!visited[j])dfsAdjoin(visited,j,n);p=p->next; //使p指向vi单链表的下一个边结点
}}
//从初始点vi出发广度优先搜索由邻接表GL表示的图
void AdjAdjoin::bfsAdjoin(bool*& visited,int i,int n)
{const int MaxLength=30;//定义一个队列q,其元素类型应为整型int q[MaxLength]={0};//定义队首和队尾指针int front=0, rear=0;//访问初始点vicout<<g[i].data<<':'<<i<<" ";//标记初始点vi已访问过visited[i]=true;//将已访问过的初始点序号i入队q[++rear]=i;//当队列非空时进行循环处理while(front!=rear) {//删除队首元素,第一次执行时k的值为ifront=(front+1)%MaxLength;int k=q[front];//取vk邻接表的表头指针edgenode* p=GL[k];while(p!=NULL){//依次搜索vk的每一个邻接点int j=p->adjvex; //vj为vk的一个邻接点if(!visited[j]) { //若vj没有被访问过则进行处理cout<<g[j].data<<':'<<j<<" ";visited[j]=true;rear=(rear+1)%MaxLength;//顶点序号j入队q[rear]=j;}p=p->next; //使p指向vk邻接表的下一个边结点
}}}
//检查输入的边序号是否越界,若越界则重输
void AdjAdjoin::Check(int n,int& i,int& j)
{while(1) {if(i<0||i>=n||j<0||j>=n)cout<<"输入有误,请重输!";else return;cin>>i>>j;}
}
//取顶点i的值
char AdjAdjoin::GetValue(const int i)
{if(i<0||i>size){cerr<<"参数i越界!\n";exit(1);}return g[i].data;
}
//取弧<v1,v2>的权
int AdjAdjoin::GetWeight(const int v1,const int v2)
{if(v1<0||v1>size||v2<0||v2>size){cerr<<"参数v1或v2越界!\n";exit(1);}edgenode *p=g[v1].adj;while(p!=NULL&&p->adjvex<v2) p=p->next;if(v2!=p->adjvex){cerr<<"边<v1,v2>不存在!\n";exit(1);}return p->weight;
}
//在位置pos处插入顶点V
void AdjAdjoin::InsertV(const char &V)
{g[size].data=V;size++;
}
//插入弧<v1,v2>,权为weight
void AdjAdjoin::InsertEdge(const int v1,const int v2,int weight)
{if(v1<0||v1>size||v2<0||v2>size){cerr<<"参数v1或v2越界!\n";exit(1);}edgenode *q=new edgenode(v2,weight);//q->adjvex=v2;q->weight=weight;if(g[v1].adj==NULL) //第一次插入g[v1].adj=q;else //非第一次插入{edgenode *curr=g[v1].adj,*pre=NULL;while(curr!=NULL&&curr->adjvex<v2){pre=curr;curr=curr->next;}if(pre==NULL) //在第一个结点前插入{q->next=g[v1].adj;g[v1].adj=q;}else //在其他位置插入{q->next=pre->next;pre->next=q;}}numE++;
}
//删除顶点v与顶点v相关的所有边
void AdjAdjoin::DeleteVE(const int v)
{edgenode *pre,*curr;for(int i=0;i<size;i++){pre=NULL; //删除顶点v的入边curr=g[i].adj;while(curr!=NULL&&curr->adjvex<v){pre=curr;curr=curr->next;}if(pre==NULL&&curr->adjvex==v){g[i].adj=curr->next; //该出边结点是链表的第一结点时delete curr;numE--;}else if(curr!=NULL&&curr->adjvex==v){pre->next=curr->next;//该出边结点是链表的其他结点时delete curr;numE--;}}edgenode *p=g[v].adj,*q;for(i=v;i<size-1;i++)g[i]=g[i+1]; //删除数组的顶点v元素numE--;while(p!=NULL)//删除顶点v的所有出边{q=p->next;delete p; //释放空间p=q;numE--;}
}
//删除弧<v1,v2>
void AdjAdjoin::DeleteEdge(const int v1,const int v2)
{if(v1<0||v1>size||v2<0||v2>size||v1==v2){cerr<<"参数v1或v2出错!\n";exit(1);}edgenode *curr=g[v1].adj,*pre=NULL;while(curr!=NULL&&curr->adjvex<v2){pre=curr;curr=curr->next;}if(pre==NULL&&curr->adjvex==v2)//要删除的结点是链表的第一结点{g[v1].adj=curr->next;delete curr;numE--;}else if(curr!=NULL&&curr->adjvex==v2)//不是链表的第一结点{pre->next=curr->next;delete curr;numE--;}else{cerr<<"边<v1,v2>不存在!\n";exit(1);}
}
//删除图的邻接表
void AdjAdjoin::DeleteAdjoin(int n)
{int i;edgenode* p;for(i=0;i<n;i++){p=GL[i];while(p!=NULL){GL[i]=p->next;delete p;p=GL[i];}}delete []GL;
}
//对非连通图进行深度优先搜索
void AdjAdjoin::dfsAdjoin(int n)
{bool *vis=new bool[NumV()];for(int i=0;i<NumV();i++) vis[i]=false;for(i=0;i<NumV();i++)if(!vis[i]) dfsAdjoin(vis,i,n);delete []vis;
}
//对非连通图进行广度优先搜索
void AdjAdjoin::bfsAdjoin(int n)
{bool *vis=new bool[NumV()];for(int i=0;i<NumV();i++) vis[i]=false;for(i=0;i<NumV();i++)if(!vis[i]) bfsAdjoin(vis,i,n);delete []vis;
}
void AdjAdjoin::CreatGraph(char V[],int n,RCW E[],int e)
{for(int i=0;i<n;i++) InsertV(V[i]);for(int k=0;k<e;k++)InsertEdge(E[k].row,E[k].col,E[k].weight);cout<<"输出建立的图:\n";for(i=0;i<n;i++)cout<<g[i].data<<" ";cout<<endl;
} //图的相关运算的测试graph1M.cpp
#include<iostream.h>
#include<iomanip.h>
#include<stdlib.h>
#include "graph1.cpp"
void main()
{cout<<"graph1M.cpp运行结果:\n";char a[]={'A','B','C','D','E','F','G'};RCW rcw[]={{0,1,1},{0,2,1},{1,3,1},{1,4,1},{2,5,1},{2,6,1},{1,0,1},{2,0,1},{3,1,1},{4,1,1},{5,2,1},{6,2,1}};//定义图的点数及搜索起始点序号等int n,k,i;//k1为0则无向否则为有向,k2为0则无权否则为有权int k1,k2;//标记已访问过的点bool *vis;cout<<"输入图的点数n=";cin>>n;vis=new bool[n];if(!vis) {cout<<"申请堆内存失败!\n";exit(1);}for(i=0;i<n;i++) vis[i]=false;cout<<"输入选择无向(权)与有向(权)图的值k1,k2:";cin>>k1>>k2;edgenode **gl=new edgenode*[n];AdjAdjoin B(gl,n);B.CreatGraph(a,n,rcw,12);cout<<"创建邻接表:\n";B.CreateAdjoin(n,k1,k2,rcw);cout<<"出发点Vk的序号=";cin>>k;cout<<"当前的顶点数为:"<<B.NumV()<<endl;cout<<"当前的边数为:"<<B.NumEdges()<<endl;cout<<"表的深度优先搜索顺序:\n";B.dfsAdjoin(vis,k,n);cout<<endl;cout<<"表的广度优先搜索顺序:\n";for(i=0;i<n;i++) vis[i]=false;B.bfsAdjoin(vis,k,n);cout<<endl;B.DeleteEdge(0,2);B.DeleteEdge(2,0);cout<<"当前的顶点数为:"<<B.NumV()<<endl;cout<<"当前的边数为:"<<B.NumEdges()<<endl;cout<<"表的深度优先搜索顺序:\n";B.dfsAdjoin(n);cout<<endl;cout<<"表的广度优先搜索顺序:\n";for(i=0;i<n;i++) vis[i]=false;B.bfsAdjoin(n);cout<<endl;B.DeleteAdjoin(n);cin.get();cin.get();
}
五、实验(训)报告要求
(1)按要求撰写实训报告,记录实验内容、实验操作方法与步骤。
(2)记录实验步骤的时候,可以只记录核心源代码。
(3)请记录实训结果及自己对结果的分析。
(4)请记录实训过程中遇到的问题以及解决方法,并可加上自己对实训的改进意见。
其他选题
1.运动会分数统计
任务:参加运动会有n个学校,学校编号为1……n。比赛分成m个男子项目,和w个女子项目。项目编号为男子1……m,女子m+1……m+w。不同的项目取前五名或前三名积分;取前五名的积分分别为:7、5、3、2、1,前三名的积分分别为:5、3、2;哪些取前五名或前三名由学生自己设定。(m<=20,n<=20)
功能要求:
1)可以输入各个项目的前三名或前五名的成绩;
2)能统计各学校总分,
3)可以按学校编号或名称、学校总分、男女团体总分排序输出;
4)可以按学校编号查询学校某个项目的情况;可以按项目编号查询取得前三或前五名的学校。
5)数据存入文件并能随时查询
6)规定:输入数据形式和范围:可以输入学校的名称,运动项目的名称
输出形式:有合理的提示,各学校分数为整形
界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。
存储结构:学生自己根据系统功能要求自己设计,但是要求运动会的相关数据要存储在数据文件中。(数据文件的数据读写方法等相关内容在c语言程序设计的书上,请自学解决)请在最后的上交资料中指明你用到的存储结构;
测试数据:要求使用1、全部合法数据;2、整体非法数据;3、局部非法数据。进行程序测试,以保证程序的稳定。测试数据及测试结果请在上交的资料中写明;
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
2.飞机订票系统
任务:通过此系统可以实现如下功能:
录入:
可以录入航班情况(数据可以存储在一个数据文件中,数据结构、具体数据自定)
查询:
可以查询某个航线的情况(如,输入航班号,查询起降时间,起飞抵达城市,航班票价,票价折扣,确定航班是否满仓);
可以输入起飞抵达城市,查询飞机航班情况;
订票:(订票情况可以存在一个数据文件中,结构自己设定)
可以订票,如果该航班已经无票,可以提供相关可选择航班;
退票: 可退票,退票后修改相关数据文件;
客户资料有姓名,证件号,订票数量及航班情况,订单要有编号。
修改航班信息:
当航班信息改变可以修改航班数据文件
要求:
根据以上功能说明,设计航班信息,订票信息的存储结构,设计程序完成功能;
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
3.文章编辑
功能:输入一页文字,程序可以统计出文字、数字、空格的个数。
静态存储一页文章,每行最多不超过80个字符,共N行;要求(1)分别统计出其中英文字母数和空格数及整篇文章总字数;(2)统计某一字符串在文章中出现的次数,并输出该次数;(3)删除某一子串,并将后面的字符前移。
存储结构使用线性表,分别用几个子函数实现相应的功能;
输入数据的形式和范围:可以输入大写、小写的英文字母、任何数字及标点符号。
输出形式:(1)分行输出用户输入的各行字符;(2)分4行输出"全部字母数"、“数字个数”、“空格个数”、“文章总字数”(3)输出删除某一字符串后的文章;
4.宿舍管理查询软件
1)任务:为宿舍管理人员编写一个宿舍管理查询软件, 程序设计要求:
A.采用交互工作方式
B.建立数据文件,数据文件按关键字(姓名、学号、房号)进行排序(冒泡、选择、插入排序等任选一种)
2)查询菜单: (用二分查找实现以下操作)
A.按姓名查询
B.按学号查询
C.按房号查询
3)打印任一查询结果(可以连续操作)
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
5.校园导航问题
设计要求:设计你的学校的平面图,至少包括10个以上的场所,每两个场所间可以有不同的路,且路长也可能不同,找出从任意场所到达另一场所的最佳路径(最短路径)。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
6.教学计划编制问题
设计要求:针对计算机系本科课程,根据课程之间的依赖关系(如离散数学应在数据结构之前开设)制定课程安排计划,并满足各学期课程数目大致相同。
7.散列法的实验研究
散列法中,散列函数构造方法多种多样,同时对于同一散列函数解决冲突的方法也可以不同。两者是影响查询算法性能的关键因素。对于几种典型的散列函数构造方法,做实验观察,不同的解决冲突方法对查询性能的影响。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
8.图书借阅管理系统
主要分为两大功能:
1)图书管理(增加图书、查询图书、删除图书、图书借阅、还书);
2)会员管理(增加会员、查询会员、删除会员、借书信息);
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
9.学生成绩管理
实现功能:输入、输出、插入、删除、查找、追加、读入、显示、保存、拷贝、排序、索引、分类合计、退出。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
10.活期储蓄帐目管理
活期储蓄处理中,储户开户、销户、存入、支出活动频繁,系统设计要求:
1)能比较迅速地找到储户的帐户,以实现存款、取款记账;
2)能比较简单,迅速地实现插入和删除,以实现开户和销户的需要。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
11.二叉排序树的实现
用顺序和二叉链表作存储结构
1)以回车(‘\n’)为输入结束标志,输入数列L,生成一棵二叉排 序树T;
2)对二叉排序树T作中序遍历,输出结果;
3)输入元素x,查找二叉排序树T,若存在含x的结点,则删除该结点,并作中序遍历(执行操作2);否则输出信息“无x”;
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
12.最小生成树问题
设计要求:在n个城市之间建设网络,只需保证连通即可,求最经济的架设方法。存储结构采用多种。求解算法多种。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
13.通讯录的制作
设计目的:用〈〈数据结构〉〉中的双向链表作数据结构,结合C语言基本知识。编写一个通讯录管理系统。以把所学数据结构知识应用到实际软件开发中去。
设计内容:本系统应完成一下几方面的功能:
1)输入信息——enter();
2)显示信息———display( );
3)查找以姓名作为关键字 ———search( );
4)删除信息———delete( );
5)存盘———save ( );
6)装入———load( ) ;
设计要求:
1)每条信息至包含 :姓名(NAME )街道(STREET)城市(CITY)邮编(EIP)国家(STATE)几项
2)作为一个完整的系统,应具有友好的界面和较强的容错能力
3)上机能正常运行,并写出课程设计报告
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
14.哈夫曼编码/译码器
【问题描述】
设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。
【基本要求】
1)将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中)
2)分别采用动态和静态存储结构
3)初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;
4)编码:利用建好的哈夫曼树生成哈夫曼编码;
5)输出编码;
6)设字符集及频度如下表:
字符 空格 A B C D E F G H I J K L M
频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20
字符 N O P Q R S T U V W X Y Z
频度 57 63 15 1 48 51 80 23 8 18 1 16 1
【进一步完成内容】
1)译码功能;
2)显示哈夫曼树;
3)界面设计的优化。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
15.图书管理系统
【问题描述】
设计一个计算机管理系统完成图书管理基本业务。
【基本要求】
1)每种书的登记内容包括书号、书名、著作者、现存量和库存量;
2)对书号建立索引表(线性表)以提高查找效率;
3)系统主要功能如下:
*采编入库:新购一种书,确定书号后,登记到图书帐目表中,如果表中已有,则只将库存量增加;
*借阅:如果一种书的现存量大于0,则借出一本,登记借阅者的书证号和归还期限,改变现存量;
*归还:注销对借阅者的登记,改变该书的现存量。
【进一步完成内容】
1)系统功能的进一步完善;
2)索引表采用树表。
3)设计内容
4)程序流程图
5)源程序
6)软件测试报告(包括所用到的数据及结果)
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
16.散列表的设计与实现
【问题描述】
设计散列表实现电话号码查找系统。
【基本要求】
1)设每个记录有下列数据项:电话号码、用户名、地址;
2)从键盘输入各记录,分别以电话号码和用户名为关键字建立散列表;
3)采用一定的方法解决冲突;
4)查找并显示给定电话号码的记录;
5)查找并显示给定用户名的记录。
【进一步完成内容】
1)系统功能的完善;
2)设计不同的散列函数,比较冲突率;
3)在散列函数确定的前提下,尝试各种不同类型处理冲突的方法,考察平均查找长度的变化。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
17.顺序结构、动态链表结构下的一元多项式的加法、减法、乘法的实现。
设有一元多项式Am(x)和Bn(x).
Am(x)=A0+A1x1+A2x2+A3x3+… +Amxm
Bn(x)=B0+B1x1+B2x2+B3x3+… +Bnxn
请实现求M(x)= Am(x)+Bn(x)、M(x)= Am(x)-Bn(x)和M(x)= Am(x)×Bn(x)。
要求:
1)首先判定多项式是否稀疏
2)分别采用顺序和动态存储结构实现;
3)结果M(x)中无重复阶项和无零系数项;
4)要求输出结果的升幂和降幂两种排列情况
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
18.利用栈求表达式的值,可供小学生作业,并能给出分数。
要求:建立试题库文件,随机产生n个题目;题目涉及加减乘除,带括弧的混合运算;随时可以退出;保留历史分数,能回顾历史,给出与历史分数比较后的评价
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
19.简易文本编辑器
要求:
1)具有图形菜单界面;
2)查找,替换(等长,不等长),插入(插串,文本块的插入)、块移动(行块,列块移动),删除
3)可正确存盘、取盘;
4)正确显示总行数。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
20.二叉树的中序、前序、后序的递归、非递归遍历算法,层次序的非递归遍历算法的实现,应包含建树的实现。
要求:遍历的内容应是千姿百态的。
树与二叉树的转换的实现。以及树的前序、后序的递归、非递归遍历算法,层次序的非递归遍历算法的实现,应包含建树的实现。
要求:遍历的内容应是千姿百态的。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
21.学生搭配问题
一班有m个女生,有n个男生(m不等于n),现要开一个舞会. 男女生分别编号坐在舞池的两边的椅子上.每曲开始时,依次从男生和女生中各出一人配对跳舞, 本曲没成功配对者坐着等待下一曲找舞伴.
请设计一系统模拟动态地显示出上述过程,要求如下:
1)输出每曲配对情况
2)计算出任何一个男生(编号为X)和任意女生(编号为Y),在第K曲配对跳舞的情况.至少求出K的两个值.
3)尽量设计出多种算法及程序,可视情况适当加分
提示:用队列来解决比较方便.
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111
22.猴子吃桃子问题
有一群猴子摘了一堆桃子,他们每天都吃当前桃子的一半且再多吃一个,到了第10天就只余下一个桃子。用多种方法实现求出原来这群猴子共摘了多少个桃子。
要求:
1)采用数组数据结构实现上述求解
2)采用链数据结构实现上述求解
3)采用递归实现上述求解
23.数制转换问题
任意给定一个M进制的数x ,请实现如下要求
1)求出此数x的10进制值(用MD表示)
2)实现对x向任意的一个非M进制的数的转换。
3)至少用两种或两种以上的方法实现上述要求(用栈解决,用数组解决,其它方法解决)。
24.排序综合
利用随机函数产生N个随机整数(20000以上),对这些数进行多种方法进行排序。
要求:
1)至少采用三种方法实现上述问题求解(提示,可采用的方法有插入排序、希尔排序、起泡排序、快速排序、选择排序、堆排序、归并排序)。并把排序后的结果保存在不同的文件中。
2)统计每一种排序方法的性能(以上机运行程序所花费的时间为准进行对比),找出其中两种较快的方法。
3)如果采用4种或4种以上的方法者,可适当加分。
25.学生成绩管理系统
现有学生成绩信息文件1(1.txt),内容如下
姓名 学号 语文 数学 英语
张明明 01 67 78 82
李成友 02 78 91 88
张辉灿 03 68 82 56
王露 04 56 45 77
陈东明 05 67 38 47
…. .. .. .. …
学生成绩信息文件2(2.txt),内容如下:
姓名 学号 语文 数学 英语
陈果 31 57 68 82
李华明 32 88 90 68
张明东 33 48 42 56
李明国 34 50 45 87
陈道亮 35 47 58 77
…. .. .. .. …
试编写一管理系统,要求如下:
1)实现对两个文件数据进行合并,生成新文件3.txt
2)抽取出三科成绩中有补考的学生并保存在一个新文件4.txt
3)合并后的文件3.txt中的数据按总分降序排序(至少采用两种排序方法实现)
4)输入一个学生姓名后,能查找到此学生的信息并输出结果(至少采用两种查找方法实现)
5)要求使用结构体,链或数组等实现上述要求.
6)采用多种方法且算法正确者,可适当加分.
26.图的遍历的实现
要求:
1)先任意创建一个图;
2)图的DFS,BFS的递归和非递归算法的实现
3)要求用有向图和无向图分别实现
4)要求用邻接矩阵、邻接表多种结构存储实现
27.线索二叉树的应用
要求:实现线索树建立、插入、删除、恢复线索的实现。
28.稀疏矩阵应用
要求:实现三元组,十字链表下的稀疏矩阵的加、转、乘的实现。
(1)稀疏矩阵的存储
(2)稀疏矩阵加法
(3)矩阵乘法
(4)矩阵转置
29.树的应用
要求:实现树与二叉树的转换的实现。以及树的前序、后序的递归、非递归算法,层次序的非递归算法的实现,应包含建树的实现。
30. 文本文件单词的检索与计数
设计要求与分析:
要求编程建立一个文本文件,每个单词不包含空格且不跨行,单词由字符序列构成且区分大小写;统计给定单词在文本文件中出现的总次数;检索输出某个单词出现在文本中的行号、在该行中出现的次数以及位置。该设计要求可分为三个部分实现:其一,建立文本文件,文件名由用户用键盘输入;其二,给定单词的计数,输入一个不含空格的单词,统计输出该单词在文本中的出现次数;其三,检索给定单词,输入一个单词,检索并输出该单词所在的行号、该行中出现的次数以及在该行中的相应位置。
(1)建立文本文件
(2)给定单词的计数
(3)检索单词出现在文本文件中的行号、次数及其位置
(4)主控菜单程序的结构
① 头文件包含
② 菜单选项包含
建立文件、单词定位、单词计数、退出程序
③ 选择1-4执行相应的操作,其他字符为非法。
31.任意长的整数加法
问题描述:设计一个程序实现两个任意长的整数的求和运算。
基本要求:利用双向循环链表,设计一个实现任意长的整数进行加法运算的演示程序。要求输入和输出每四位一组,组间用逗号隔开。如:1,0000,0000,0000,0000。
32. 二叉平衡排序树
问题描述:从一棵空树开始创建,在创建过程中,保证树的有序性,同时还要针对树的平衡性做些调整。最终要把创建好的二叉排序树转换为二叉平衡排序树。
基本要求:1.创建(插入、调整、改组)
2.输出
33.串的查找和替换
问题描述:打开一篇英文文章,在该文章中找出所有给定的单词,然后对所有给定的单词替换为另外一个单词,再存盘。
34.约瑟夫环
问题描述:编号为1,2… n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他的顺时针方向上的下一个开始重新从1报数,如此下去,直至所有人全部出列为止,设计一个程序求出出列顺序。
基本要求:
1、利用单循环链表作为存储结构模拟此过程;
2、键盘输入总人数、初始报数上限值m及各人密码;
3、按照出列顺序输出各人的编号。
35.构造可以使n个城市连接的最小生成树
问题描述:给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
基本要求:
1、城市间的距离网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
2、表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)
3、最小生成树中包括的边及其权值,并显示得到的最小生成树的代价。
36.客户消费积分管理系统
问题描述:针对客户的消费情况,进行客户管理,根据客户的消费积分对客户实行不同程度的打折优惠。
基本要求:
- 采用一定的存储结构进行客户信息的存储;
- 对客户的信息可以进行修改、删除、添加;
- 能够根据消费情况进行客户积分的计算;
- 根据积分情况实行不同程度的打折优惠;
37.产品进销存管理系统
问题描述:针对某一种行业的库房的产品进销存情况进行管理。
基本要求:
- 采用一定的存储结构对库房的货品及其数量进行分类管理;
- 可以进行产品类的添加、产品的添加、产品数量的添加;
- 能够查询库房每种产品的总量、进货日期、销出数量、销售时间等;
38. 特殊矩阵的压缩存储算法的实现
问题描述:对于特殊矩阵可以通过压缩存储减少存储空间。
基本要求:
1.针对多种特殊矩阵进行压缩存储,并能显示压缩后的相关地址和值;
2.输入在原来特殊矩阵中的地址,要求能从压缩后的矩阵中读出相应的值;
39.算术表达式的求解
问题描述:给定一个算术表达式,通过程序求出最后的结果。
基本要求:
1. 从键盘输入要求解的算术表达式;
2. 采用栈结构进行算术表达式的求解过程;
3. 能够判断算术表达式正确与否;
4. 对于错误表达式给出提示;
5. 对于正确的表达式给出最后的结果;
40.实时监控报警系统
问题描述:建立一个报警和出警管理的系统
基本要求:
- 采用一定的存储结构存储报警信息,要求有内容、时间;
- 有一次的出警就应该在待处理的信息中删除这条信息;
- 记录出警信息;
- 待处理信息过多时会发出警告;
41. 车厢调度
问题描述:假设停在铁路调度站入口处的车厢序列的编号一次为1,2,3,4。设计一个程序,求出所有可能由此输出的长度为4的车厢序列。
42.迷宫问题(栈)
问题描述:
以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
基本要求:
首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。求得的通路以三元组(i,j,d)的形式输出,其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向,如:对于下列数据的迷宫,输出的一条通路为:(1,1,1),(1,2,2),(3,2,3),(3,1,2),…。
测试数据:
迷宫的测试数据如下:左下角(1,1)为入口,右下角(8,9)为出口。
实现提示:
计算机解迷宫通常用的是“穷举求解”方法,即从入口出发,顺着某个方向进行探索,若能走通,则继续往前进;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。假如所有可能的通路都探索到而未能到达出口,则所设的迷宫没有通路。
可以二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。为处理方便起见,可在迷宫的四周加一圈障碍。对于迷宫中任一位置,均可约定有东、南、西、北四个方向可通。
选做内容:
(1)编写递归形式的算法,求得迷宫中所有可能的通路;
(2)以方阵形式输出迷宫及其通路。
43.迷宫问题(队列)(同上)
44二叉搜索树:各种搜索树效率比较
题目要求:
本题目要求对普通的二叉排序树、AVL树分别实现制定操作,并分析比较这两种不同数据结构对应的一系列插入和删除操作的效率。要求测试对N个不同整数进行下列操作的效率:
(1) 按递增顺序插入N个整数,并按同样顺序删除;
(2) 按递增顺序插入N个整数,并按相反顺序删除;
(3) 按随机顺序插入N个整数,并按随机顺序删除;
要求N从1000到10000取值,并以数据规模N为横轴,运行时间为纵轴,画出3种不同数据结构对应的操作效率比较图。
45. 病毒测试程序
本题的任务是:
当整个网络被感染后,计算有多少台机器被某个特定变种所感染。
输入要求:
输入由若干组测试数据组成。
每组数据的第1行包含2个整数M和N(1≤M,N≤500),接下来是一个M*N的矩阵表示网络的初始感染状态,其中的正、负整数的意义如题目描述中所定义。
下面一行给出一个正整数Q,是将要查询的变种的个数。接下去的Q行里,每行给出一个变种的类型。
当M或N为0时,表示全部测试结束,不要对该数据做任何处理。
输出要求:
对每一组测试,在一行里输出被某个特定变种所感染的机器数量。
46关键路径问题
问题描述:设计一个程序求出完成整项工程至少需要多少时间以及整项工程中的关键活动。
基本要求:
(1)对一个描述工程的AOE网,应判断其是否能够顺利进行。
(2)若该工程能顺利进行,输出完成整项工程至少需要多少时间,以及每一个关键活动所依附的两个顶点、最早发生时间、最迟发生时间。
47.神秘国度的爱情故事
输入要求:输入由若干组测试数据组成。
每组数据的第1行包含一正整数N(1≤N≤50000),代表神秘国度中小村的个数,每个小村即从0到N-1编号。接下来有N-1行输入,每行包含一条双向道路的两端小村的编号,中间用空格分开。之后一行包含一正整数M(1≤M≤500000),代表着该组测试问题的个数。接下来M行,每行给出A,B,C三个小村 的编号,中间用空格分开。
当N为0时,表示全部测试结束,不要对该数据做任何处理。
输出要求:对每一组测试给定的A,B,C,在一行里输出答案,即:如果C在A和B之间的路径上,输出Yes,否则输出No。
48.并查集:检查网络
题目要求:给定一个计算机网络以及机器间的双向连线列表,每一条连线允许两端的计算机进行直接的文件传输,其他计算机间若存在一条连通路径,也可以进行间接的文件传输。请写出程序判断:任意指定两台计算机,它们之间是否可以进行文件传输?
输入要求:输入若干测试数据组成。对于每一组测试,第1行包含一个整数N(≤10000),即网络中计算机的总台数,因而每台计算机可用1到N之间的一个正整数表示。接下来的几行输入格式为I C1 C2或者 C或者C C1C2或者S,其中C1和C2是两台计算机的序号,I表示在C1和C2间输入一条连线,C表示检查C1和C2间是否可以传输文件,S表示该组测试结束。
当N为0时,表示全部测试结束,不要对该数据做任何处理。
输出要求:对每一组C开头的测试,检查C1和C2间是否可以传输文件,若可以,则在一行中输出“yes”,否则输出“no”。
当读到S时,检查整个网络。若网络中任意两机器间都可以传输文件,则在一行中输出“The network is connected.”,否则输出“There are k components.”,其中k是网络中连通集的个数。
两组测试数据之间请输出一空行分隔。
49.广义表的应用
由于广义表在结构上较线性表复杂得多,因此,广义表的运算也不如线性表简单。本设计要求实现的广义表的建立、查找、输出、取表头和取表尾以及求深度、求逆表等。
本设计用一个主控菜单程序控制,共分为6个子系统。
(1).建立广义表
(2)输出广义表
(3)结点的查找
(4)求广义表表头
(5)求广义表表尾
(6)求广义表的深度
50.网络流:宇宙旅行
题目要求:
在走遍了地球上的所有景点以后,旅游狂人开始计划他的宇宙旅行项目。经过谨慎调查,他目前掌握了一张各卫星空间站可以临时容纳的旅客人数列表。但旅客从一个星球飞往另一个星球时,需要在若干卫星空间站临时停靠中转,而这些空间站不能接待任何旅客驻留,旅客必须立刻转乘另一艘飞船离开,所以空间站不能接待超过自己最大容量的旅客流。为了估计预算,现在旅游狂人需要知道终点星球的接待站应该设计多大容量,才能使得每艘飞船在到达时都可以保证让全部旅客下船。
输入要求:
输入若干组测试数据组成。
每组测试数据的第1行包含旅行的起点星球和终点星球的名称和一个不超过500的正整数N(N为0标志全部测试结束,不要对该数据做任何处理)。
接下来的N行里,数据格式为:sourcei capacityi ,其中sourcei和destinationi是卫星空间站的名称或起点、终点星球的名称,正整数capacityi是飞船从sourcei到destinationi一次能运载的最大旅客流量。每个名称是由A~Z之间三个大写字母组成的字符串,例如:ZJU。
测试数据中不包含任何到达起点星球的信息以及任何从终点星球出发的信息。
输出要求:
对每一组测试,在一行里输出终点星球接待站应具有的最小容量,使得每艘飞船在到达时都可以保证让全部旅客下船。
源码
https://pan.baidu.com/s/1pq1Nwwo0hlc_J84F93HM4A?pwd=1111