欢迎大家访问我的博客,www.huangrd.top学习更多内容。
title: 数据结构实验
date: 2022-11-22 09:15:30
categories:
- 算法
tags: - 算法
- 数据结构
- 实验
数据结构实验
线性表的应用
一.实验目的
-
掌握线性表的单链表实现与静态链表实现。
-
掌握线性表的应用:运动会信息管理系统。
二. 实验要求、内容
- 基于单链表实现线性表 List1 的典型操作(判空、判满、求表长、插入、删除、查找、修改、遍历、置空、普
通构造、拷贝构造、赋值运算符重载、析构),编写简单程序使用该线性表,测试和调试程序。
- 基于静态链表实现线性表 List2 的典型操作(判空、判满、求表长、插入、删除、查找、修改、遍历、置空、
普通构造),编写简单程序使用该线性表,测试和调试程序。
-
基于线性表 List1、线性表 List2 实现线性表的应用:运动会信息管理,测试和调试程序。
-
按要求撰写实验报告、录制程序运行以及讲解程序的视频。报告中要包含算法性能的讨论以及根据实现效率
在问题的多种解决方案中进行比较、选择的说明。
三.实验设备
计算机、Windows 操作系统、C++语言集成开发环境。
四.实验原理(或程序框图)及步骤
*实验1*
1.问题分解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6j2ME2nd-1669079859446)(数据结构实验/wps2.jpg)]
链表中每个节点包含 1 个数据域(entry)和 1 个指针域(next),指向下一个节点。采用模板完成节点的定义。
- 对问题一基于单链表实现线性表List1的典型操作。
(1) .构造方法
对线性表进行初始化,因为是单链表,就让count计数器为0,让next指针为空。
时间复杂度:O(1)
template<class List_entry> List1<List_entry>::List1() {
//对线性表初始化
count = 0;
head = nullptr;
}
(2) .析构方法
对线性表进行清空,析构借助他的clear()方法,如果线性表不为空,则把线性表清空。
时间复杂度:O(N)
template<class List_entry> List1<List_entry>::~List1() {
//借助clear()方法清空
clear();
}
(3) .clear()置空方法
相当于单链表的清空表,从表头遍历链表,途中对每一个节点进行置空,并通过delete来删除节点,最后对count计数器和head头指针进行初始化。
时间复杂度:O(N)
template<class List_entry> void List1<List_entry>::clear() {
Node<List_entry>* p, * q;
//p 当前节点 q next节点
for (p = head; p; p = q) {
q = p->next;
delete p;
}
count = 0;
head = nullptr;
}
(4) .size()求表长
通过返回count计数器。时间复杂度:O(1)
template<class List_entry> int List1<List_entry>::size()const {
return count;
}
(5) .full()判满
因为是单链表实现所以只要一直有内存空间就不可能存在满的情况,直接返回false。
时间复杂度:O(1)
template<class List_entry> bool List1<List_entry>::full() const {
return false;
}
(6) .empty()判空
如果头节点为空,则说明线性表为空,如果头节点不为空,则说明线性表不为空。
时间复杂度:O(1)
template<class List_entry> bool List1<List_entry>::empty()const {
if (head != nullptr) return false;
else return true;
}
(7) .set_position()找位置
先判断找的位置的下标是否符合规范,当符合规范时,把链表从表头开始,遍历position次,来到要找的节点位置,返回当前位置。时间复杂度:O(N)
template <class List_entry> Node<List_entry>* List1<List_entry>::set_position(int position) const {
Node<List_entry>* q = head;
//遍历position次就来到了position的节点位置
for (int i = 0; i < position; i++) q = q->next;
return q;
}
(8) .insert()插入方法
先看插入的位置是否符合规范,如果符合规范,通过set_position()方法找到前一个节点,new一个新的节点,让前一个节点的next指针域指向新节点,而让新节点的next指针域指向前一个结点老的next域(也就是下一个节点)。
时间复杂度:O(N)
template <class List_entry> Error_code List1<List_entry>::insert(int position, const List_entry& x) {
if (position < 0 || position > count) //position的位置不合法
return range_errors;
Node<List_entry>* new_node, //新节点
\* previous, //前驱节点
\* following;//后继节点
previous = nullptr;
if (position > 0) { //不是头插
previous = set_position(position - 1);//找到他的前驱节点
following = previous->next;//后继节点
}
else following = head;//是头插的话,没有前驱,后继就是原来的头节点
new_node = new Node<List_entry>(x, following);//借用了node的构造方法 //node->next = following
if (new_node == nullptr)
return overflow;
if (position == 0)//如果是头插的话,头节点就是插入的new_node
head = new_node;
else//不是头插的话,就让前驱节点的next指向new_node
previous->next = new_node;
count++;
return success;
}
(9) .traverse()方法
遍历当前列表,通过传入的指针函数,对每一个节点都用传入的函数来操作。
时间复杂度:O(N)
template <class List_entry> void List1<List_entry>::traverse(void (*visit) (List_entry&)) {
Node<List_entry>* q;
for (q = head; q; q = q->next) { //遍历每一个节点 对每一个节点 通过函数指针来进行操作
(*visit) (q->entry);
}
}
(10) .remove()删除节点
先判断表是否为空,再判断要删除的位置是否符合规范,如果都满足,判断是不是头节点(删除的位置是不是0),如果不是就通过set_position()方法来找到要删除节点的前一个节点,让前一个节点的next指针域指向要删除节点的next指针域。如果要删除的是头节点,就直接让下一个节点作为头结点。
时间复杂度:O(N)
template<class List_entry> Error_code List1<List_entry>::remove(int position, List_entry& x) {
Node<List_entry>* prior,//前驱节点
\* current;//当前节点
if (empty()) return fail;
if (position < 0 || position >= count) return range_errors;//position位置是否合法
if (position > 0) { //删的不是头节点
prior = set_position(position - 1);//前驱
current = prior->next;//当前
prior->next = current->next;//让前驱节点绕过当前节点直接指到后继节点
}
else { //删除头节点
current = head;
head = head->next;
}
x = current->entry;//x带出要删除节点的值
delete current;//通过delete删除节点
count--;
return success;
}
(11) .retrieve()访问方法
先判断要访问的位置是否符合规范,如果符合规范就通过set_position方法来找到当前节点,通过x把当前节点的值带出去。
时间复杂度:O(N)
template<class List_entry> Error_code List1<List_entry>::retrieve(int position,List_entry& x) const {
Node<List_entry>* current;
if (position < 0 || position >= count) return range_errors;//position位置是否合法
current = set_position(position);//通过set_position拿到当前节点
x = current->entry;
return success;
}
(12) .replace()替换方法
先判断要替换的位置是否符合规范,如果符合规范就通过set_position方法来找到当前节点,把x的值赋给当前节点的数据域完成替换。
时间复杂度:O(N)
template<class List_entry> Error_code List1<List_entry>::replace(int position, const List_entry& x) {
Node<List_entry>* current;
if (position < 0 || position >= count) return range_errors;
current = set_position(position);
current->entry = x;
return success;
}
(13) .拷贝构造
和链表的拷贝构造类似,先通过头节点创造一个新节点,再遍历老链表,Node结构体有一个构造方法,会把上一个点的next指针域指向当前新建的节点,通过该方法不断创造新节点来对老链表进行拷贝。
时间复杂度:O(N)
template<class List_entry> List1<List_entry>::List1(const List1<List_entry>& copy) {//拷贝构造
count = copy.count;
Node<List_entry>* new_node, * old_node = copy.head;
if (old_node == nullptr) head = nullptr;
else {
new_node = new Node<List_entry>();
head = new_node;
while (old_node != nullptr) { //遍历拷贝的线性表
old_node = old_node->next;
new_node->next = new Node<List_entry>(old_node->entry);
new_node = new_node->next;//new_node往后拨一个
}
}
}
(14) .赋值运算符重载
借助拷贝构造函数,拷贝一个新线性表,把当前线性表置空,让新线性表的指针域作为当前线性表的指针域,删除新的线性表头节点,即可。
时间复杂度:O(N)
template<class List_entry>
void List1<List_entry>::operator =(const List1<List_entry>& copy) { //赋值运算符重载
List1 new_copy(copy);//借用拷贝构造
clear();//清空当前表
count = 0;
head = nullptr;
new_copy.count = copy.count;
new_copy.head = head;
}
*实验2*
1.问题分解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JKGNzce8-1669079859447)(数据结构实验/wps3.jpg)]
静态链表的底层实际上是数组,每个节点包含 1 个数据域(entry 数组存放的值)和 1 个“指针域”(next 其实不是指针,是指下标),指向下一个节点。
\2. 对问题一基于单链表实现线性表List2的典型操作。
(1) .构造方法
对线性表进行初始化,首先要弄清楚他的属性available(可获得的空间链表的头指针 数组的下标), last_used(上一次使用的空间 相当于指针 数组下标), head(静态链表的头指针 也是数组下标)。在对线性表初始化的时候,就让上边的三个指针全部设初值为-1,在数组中表示无空间,就是nullptr的意思,让count的计数器的值为0。
时间复杂度:O(1)
template<class List_entry>
List2<List_entry>::List2()
{
//初始化
//都假定为空 -1
available = -1;
last_used = -1;
head = -1;
count = 0;
}
(2) .clear()置空方法
静态链表的的清空操作,从表头遍历静态链表,通过delete_node()方法删除节点(其实是加到了available链表中)。
时间复杂度:O(N)
template<class List_entry>
void List2<List_entry>::clear()
{
index p, q;
for (p = head; p != -1; p = workspace[p].next) { //遍历链表 对每一个节点进行delete_node
q = p;
delete_node(p);
}
count = 0;
head = -1;
}
(3) .size()求表长
通过返回count计数器。
时间复杂度:O(1)
template<class List_entry>
int List2<List_entry>::size() const{
return count;
}
(4) .full()判满
静态链表的底层是数组实现的,所以比较count计数器和max_list(数组容量)的大小。
时间复杂度:O(1)
template<class List_entry>
bool List2<List_entry>::full() const
{
return count < max_list;
}
(5) .empty()判空
判断count计数器是否为0。时间复杂度:O(1)
template<class List_entry>
bool List2<List_entry>::empty() const {
return count == 0;
}
(6) .set_position()找位置
把静态链表从表头开始,遍历position次,来到要找的节点位置,返回当前位置。
时间复杂度:O(N)
template <class List_entry>
index List2<List_entry>::set_position(int position) const { //根据下标,获得当前的值
//Node2<List_entry> p;
int i = 0;
int cnt = 0;
if (!(position<0 || position>max_list)) {
//遍历position次 拿到position的节点
for (i = head; cnt < position; cnt++, i = workspace[i].next);
}
return i;
}
(7) .insert()插入方法
先看插入的位置是否符合规范,如果符合规范,通过set_position()方法找到前一个节点,通过new_node()方法创建一个新的节点,让前一个节点的next指针域指向新节点,而让新节点的next指针域指向前一个结点老的next域(也就是下一个节点)。
时间复杂度:O(N)
template <class List_entry>
Error_code List2<List_entry>::insert(int position, const List_entry& x) {
index new_index, previous, following;
//判断position位置是否合法
if (position < 0 || position > count) return range_errors;
//不是头插
if (position > 0) {
//找到前驱节点 和 后继节点
previous = set_position(position - 1);
following = workspace[previous].next;
}
//头插 后继就是头节点
else following = head;
if ((new_index = new_node()) == -1) return overflow;//新建节点
workspace[new_index].entry = x;
workspace[new_index].next = following;//next域为他的后继
if (position == 0) //如果是头插 新的头节点就是new_node
head = new_index;
else //不是头插的话 处理他的前驱节点
workspace[previous].next = new_index;
count++;
return success;
}
(8) .traverse()方法
遍历当前列表,通过传入的指针函数,对每一个节点都用传入的函数来操作。
时间复杂度:O(N)
template <class List_entry>
void List2<List_entry>::traverse(void (*visit)(List_entry&)) {
//遍历链表
for (index n = head; n != -1; n = workspace[n].next)//n != -1 n != nullptr
(*visit)(workspace[n].entry);
}
(9) .remove()删除节点
通过set_position()方法来找到要当前要删除节点的节点,通过x把当前要删除结点的值带出来,通过delete_node()方法删除节点。
时间复杂度:O(N)
template<class List_entry>
Error_code List2<List_entry>::remove(int position, List_entry& x) { //析出position位置的节点
x = workspace[set_position(position)].entry;//set_position找到节点
delete_node(set_position(position));//set_position找到节点 delete_node进行删除
count--;
return success;
}
(10) .retrieve()访问方法
先判断要访问的位置是否符合规范,如果符合规范就通过set_position方法来找到当前节点,通过x把当前节点的值带出去。
时间复杂度:O(N)
template<class List_entry>
Error_code List2<List_entry>::retrieve(int position, List_entry& x) const { //访问position位置的值,通过x带出来
if (position < 0 || position > count) return range_errors;//判断position位置合不合法
int cnt = 0, i;
for (i = head; cnt != position; cnt++, i = workspace[i].next);//遍历的方式找到position位置
x = workspace[i].entry;
return success;
}
(11) .replace()替换方法
先判断要替换的位置是否符合规范,如果符合规范就通过set_position方法来找到当前节点,把x的值赋给当前节点的数据域完成替换。
时间复杂度:O(N)
template<class List_entry>
Error_code List2<List_entry>::replace(int position, const List_entry &x) {
if (position < 0 || position > count) return range_errors;//判断下标合不合法
workspace[set_position(position)].entry = x;//set_position找到position位置的节点 替换值
return success;
}
(12) .new_node()方法创建一个新空间
先看可用空间链表available是不是还有剩余的空间,如果有的话就把available链表的下一个元素给返回,如果available链表没有剩余空间了,就看整个表的空间是不是满了,如果没满的话,就把last_used++,完成新建节点。
时间复杂度:O(1)
template <class List_entry>
index List2<List_entry>::new_node(){
index new_index;
//因为是数组下标 用-1代替nullptr
/*
\* 1. 先看available有没有空间可以用
\* 2. available表没空间了,看能不能新建
\* */
if (available != -1) { //available有空间可以用
new_index = available;//available把头节点给new_node
available = workspace[available].next;//自己跳到下一个节点
}
else if (last_used < max_list - 1) { //available表没有空间可以用 链表的容量没超过最大容量
new_index = ++last_used;//新建
}
else return -1;//如果方式1、2都没有新建成功,返回-1表示失败
workspace[new_index].next = -1;//新节点的next域置空
return new_index;//成功的话 返回新节点
}
(13) .delete_node()方法删除节点
删除节点要注意的是:并不是真的删除,而是把当前的链表的节点加到available链表(可用空间链表)中去。
时间复杂度:O(N^2)
template <class List_entry>
void List2<List_entry>::delete_node(index old_index) {
index previous;
if (old_index == head) //删头节点 让head为原来头结点的next
head = workspace[old_index].next;
else { //删除的其他节点
previous = set_position(current_position(old_index) - 1);//通过set_position拿到前驱节点
workspace[previous].next = workspace[old_index].next;//让前驱节点等于待删节点的后继
}
workspace[old_index].next = available;//通过头插的方式把节点添加在available表中
available = old_index;
}
(14) .current_position()方法 返回当前的位置
通过把静态链表遍历count次,来返回当前位置的节点。
时间复杂度:O(N)
template<class List_entry>
int List2<List_entry>::current_position(index n) const { //根据节点 来获取下标
int cnt = 0;
for (int i = head; i != n; cnt++, i = workspace[i].next);
return cnt;
}
实验3
\1. 问题分解
运动会项目类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hd23GjgW-1669079859448)(数据结构实验/wps4.jpg)]
运动员类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yNgLK83I-1669079859448)(数据结构实验/wps5.jpg)]
学院类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOuEfkLD-1669079859449)(数据结构实验/wps6.jpg)]
创建三个类的线性表进行操作,通过目录连接起来。
- 基于线性表 List1、线性表 List2 实现线性表的应用:运动会信息管理,测试和调试程序。
l 用List1来存放运动会项目
l 用List2来存放运动员
l 用STL库中的vector存放学院
get()set()方法较为简单,见程序源代码。
分析相关的函数操作:
注:分析时间复杂度时,不考虑线性表本身的时间开销。
(1) .运动会项目
A. void setMatch()新建项目
利用线性表的插入功能,通过构造一个match对象来把match对象通过insert()到matchs线性表中。通过IO流写道磁盘中。
时间复杂度:O(1)
void setMatch() //新建项目
{ ofstream fout("D:\\比赛项目.dat",ios::app);
char ch;
do
{ cout<<"请分别输入比赛项目名称、编号(假设为 6 位数字)、参与该项目的运动员性别、比赛 日期、比赛时间、比赛人数."<<endl;
string call;
int number;
string sex;
string date;
string time;
int num;
cin>>call>>number>>sex>>date>>time>>num;//输入相关属性
Match temp = Match(call,number,sex,date,time,num);//创建一个temp临时变量
matchs.insert(0,temp);//头插在链表中
fout.write((char *)&temp,sizeof(Match));//写入文件流
cout<<"是否继续输入,如果继续键入Y|y"<<endl;
cin>>ch;
}while(ch=='y'||ch=='Y');
fout.close();
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fESYvODc-1669079859450)(数据结构实验/wps7.jpg)]
B. int changeMatch()修改一个项目
因为所有项目中最特殊的就是项目的id唯一,所以修改只能通过查询id来完成,遍历线性表,找到要修改的项目,根据提示完成要修改的信息,通过replace()函数,完成修改的操作。
时间复杂度:O(N)
void changeMatch() //修改一个项目
{
cout<<"您正在进行修改比赛项目有关事项操作!"<<endl;
cout<<"请输入要修改比赛项目的编号:"<<endl;
int number1; //要修改的比赛项目编号
int sign=0; //设置的标记变量
cin>>number1;
int i = 0;
for (; i < matchs.size(); i++) { //遍历表 找指定的项目编号
Match temp;
matchs.retrieve(i,temp);
if (number1 == temp.getNumber()){
sign = 1;
break;
}
}
//没找到的话 输出信息提示
if (sign==0)
cout<<"没有找到要修改的记录!"<<endl;
else //找到了项目
{
cout<<"请选择要修改比赛项目的那些信息"<<endl;
cout<<"------修改比赛项目的名称----1"<<endl;
cout<<"------修改比赛项目的编号----2"<<endl;
cout<<"------修改比赛项目的性别----3"<<endl;
cout<<"------修改比赛日期----4"<<endl;
cout<<"------修改比赛时间----5"<<endl;
cout<<"------修改比赛人数----6"<<endl;
cout<<"请输入对应信息的编号"<<endl;
int a;
cin>>a;
switch(a) //switch case 控制修改的那一部分
{
case 1:{
cout<<"请输入新的比赛项目名称:"<<endl;
string name;
cin>>name;
Match temp;
matchs.retrieve(i,temp);//通过上次标记的i 拿出来找到的项目
temp.setCall(name);//修改项目姓名
matchs.replace(i,temp);//对表中的数据进行替换
cout<<"比赛项目名称修改成功!"<<endl;
break;
}
case 2:{
cout << "请输入新的比赛编号:" << endl;
int number;
cin>>number;
Match match;
matchs.remove(i,match);
match.setNumber(number);
matchs.insert(i,match);
cout << "比赛项目编号修改成功!" << endl;
break;
}
case 3:{
cout<<"请输入新的参赛选手性别:"<<endl;
string sex;
cin>>sex;
Match match;
matchs.remove(i,match);
match.setSex(sex);
matchs.insert(i,match);
cout<<"参赛选手性别修改成功!"<<endl;
break;
}
case 4:{
cout<<"请输入新的日期:"<<endl;
string date;
cin>>date;
Match match;
matchs.remove(i,match);
match.setDate(date);
matchs.insert(i,match);
cout<<"比赛日期修改成功!"<<endl;
break;
}
case 5:{
cout<<"请输入新的比赛时间:"<<endl;
string time;
cin>>time;
Match match;
matchs.remove(i,match);
match.setDate(time);
matchs.insert(i,match);
cout<<"比赛时间修改成功!"<<endl;
break;
}
case 6:{
cout<<"请输入新的参赛人数:"<<endl;
int num;
cin>>num;
Match match;
matchs.remove(i,match);
match.setNum(num);
matchs.insert(i,match);
cout<<"参赛人数修改成功!"<<endl;
break;
}
}
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHymv20A-1669079859451)(数据结构实验/wps8.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Kgw4Gig-1669079859451)(数据结构实验/wps9.jpg)]
C. void deleteMatch()删除一个项目
删除一个项目,可以通过id来进行删除,也可以通过项目名称来删除,遍历线性表,找到需要删除的数据,通过线性表的remove()操作对项目进行删除。
时间复杂度:O(N)
void deleteMatch() //删除一个项目
{
cout<<"------根据比赛项目的编号删除----1"<<endl;
cout<<"------根据比赛项目的名称删除----2"<<endl;
int n;
cin>>n;
switch(n) {
case 1: {
cout << "请输入要删除的比赛编号" << endl;
int number;
cin >> number;
Match temp;
int i = 0;
bool isFind = false;//标记
for (; i < matchs.size(); i++) { //遍历整个表 如果找到 就通过remove进行删除
matchs.retrieve(i, temp);
if (temp.getNumber() == number) {
cout << "找到信息" << endl;
matchs.remove(i, temp);
cout << "删除成功" << endl;
isFind = true;
}
}
//没找到的话 输出信息提示
if (!isFind) cout << "未找到该项目" << endl;
break;
}
case 2: {
cout << "请输入要删除的比赛名称" << endl;
string name;
cin >> name;
Match temp;
int i = 0;
bool isFind = false;
for (; i < matchs.size(); i++) {
matchs.retrieve(i, temp);
if (temp.getCall() == name) {
cout << "找到信息" << endl;
matchs.remove(i, temp);
cout << "删除成功" << endl;
isFind = true;
}
}
//没找到的话 输出信息提示
if (!isFind) cout << "未找到该项目" << endl;
break;
}
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VGyx3O04-1669079859452)(数据结构实验/wps10.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DBQn2hS2-1669079859452)(数据结构实验/wps11.jpg)]
D. void selectMatch()查询一个项目
查询一个项目,可以通过id来进行查询,也可以通过项目名称来查询,遍历线性表,找到需要查询的数据,将该信息进行输出。
时间复杂度:O(N)
void selectMatch() //查询一个项目
{
cout<<"------根据比赛项目的编号查找----1"<<endl;
cout<<"------根据比赛项目的名称查找----2"<<endl;
int n;
cin>>n;
switch(n) {
case 1: {
cout << "请输入要查找的比赛编号" << endl;
int number;
cin >> number;
Match temp;
int i = 0;
bool isFind = false;//标志位
for (; i < matchs.size(); i++) { //遍历整张表 如果找到 让标志位设为true
matchs.retrieve(i, temp);
if (temp.getNumber() == number) { //找到信息的话 就把相关的信息进行输出
cout << "找到信息:" << endl;
cout<<temp.getNumber()<<" " <<temp.getCall()<<" "<<temp.getSex()<<" "<<temp.getDate()<<" "<<temp.getTime()<<" "<<temp.getNum()<<endl;
isFind = true;
}
}
//没找到的话 输出信息提示
if (!isFind) cout << "未找到该项目" << endl;
break;
}
case 2: {
cout << "请输入要删除的比赛名称" << endl;
string name;
cin >> name;
Match temp;
int i = 0;
bool isFind = false;
for (; i < matchs.size(); i++) {
matchs.retrieve(i, temp);
if (temp.getCall() == name) {
cout << "找到信息:" << endl;
cout<<temp.getNumber()<<" " <<temp.getCall()<<" "<<temp.getSex()<<" "<<temp.getDate()<<" "<<temp.getTime()<<" "<<temp.getNum()<<endl;
isFind = true;
}
}
if (!isFind) cout << "未找到该项目" << endl;
break;
}
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-weWl7X4T-1669079859453)(数据结构实验/wps12.jpg)]
(2) .运动员
A. void inputAthlete()新建运动员
利用线性表的插入功能,通过构造一个aehlete对象来把aehlete对象通过insert()到aehletes线性表中。通过IO流写道磁盘中。
时间复杂度:O(1)
void inputAthlete()//创建运动员
{ ofstream fout("d:\\运动员.dat",ios::app);//打开文件
int i = 0;
char ch;
do
{ cout<<"请分别输入运动员姓名,学号,性别,学院,参加的项目标号"<<endl;
string name;
string id;
string sex;
string college;
string matchId;
cin>>name>>id>>sex>>college>>matchId;//输入相关信息
Athlete temp(name,id,sex,college,matchId);//创建temp对象
athletes.insert(i,temp);//插入到线性表中
fout.write((char *)&temp,sizeof(Athlete));//写入文件
cout<<"是否继续输入,如果继续键入Y|y"<<endl;
cin>>ch;
}while(ch=='y'||ch=='Y');
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRW7Ml2D-1669079859454)(数据结构实验/wps13.jpg)]
B. Void deleteAthlete()撤销报名
同理,因为所有运动员中最特殊的就是运动员的学号id唯一,所以撤销报名只能通过查询id来完成,遍历线性表,找到要修改的撤销报名的运动员,通过remove()函数,完成修改的操作。
时间复杂度:O(N)
void deleteAthlete()//撤销报名 (删除运动员)
{
//只有学号是唯一的,所以根据学号来撤销报名
cout<<"请输入被撤销报名的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;//标志位
for (int i = 0; i < athletes.size(); i++) { //遍历表 来寻找
athletes.retrieve(i,temp);
if (temp.getId() == id) {//找到 通过remove移除
athletes.remove(i,temp);
cout<<"删除成功"<<endl;
flag = true;
break;
}
}
//未找到运动员 输出信息进行提示
if (!flag) {
cout<<"未找到该运动员"<<endl;
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HKdTUWA5-1669079859455)(数据结构实验/wps14.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3T4gCtqT-1669079859455)(数据结构实验/wps15.jpg)]
C. void cheekAthlete()对运动员检录
因为所有运动员中最特殊的就是运动员的学号id唯一,所以对运动员检录只能通过查询id来完成,遍历线性表,找到要检录的运动员,通过retrieve()函数把值flag拿出来检录后通过replace()完成替换,完成修改的操作。
时间复杂度:O(N)
void cheekAthlete(){//对运动员检录
cout<<"请输入要检录的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;
for (int i = 0; i < athletes.size(); i++) {//遍历线性表
athletes.retrieve(i,temp);
if (temp.getId() == id) { //如果找到了
if (temp.isText1()) { //先看有没有检录过
cout<<"已经检录过了"<<endl;
flag = true;
break;
}else{ //没检录过 检录 replace替换表的数据
temp.setIsText(true);
athletes.replace(i,temp);
cout<<"检录成功"<<endl;
flag = true;
break;
}
}
}
//没找到的话给出提示信息
if (!flag) {
cout<<"未找到该运动员"<<endl;
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T00eHLDA-1669079859456)(数据结构实验/wps16.jpg)]
D. void loginScoreAthlete()登记运动员的成绩
某项比赛完成后,录入参加比赛同学的成绩、排名,并自动获得分数。通过对输入的排名进行访问,根据不同的排名来对运动员的成绩属性赋不同的值。
时间复杂度:O(N)
void loginScoreAthlete(){//等级运动员的信息
cout<<"请输入要录入分数的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
cout<<"请输入该运动员的成绩 和 排名"<<endl;
string score;
int rank;
cin>>score;//成绩
cin>>rank;//排名
bool flag =false;
for (int i = 0; i < athletes.size(); i++) { //遍历整个表 找到要登记成绩的学生
athletes.retrieve(i,temp);
if (temp.getId() == id && temp.isText1()) {//如果id查到,并且检录过了
temp.setScore(score);
temp.setRank(rank);//登记信息
athletes.replace(i,temp);//替换表中的数据
cout<<"成绩录入完成"<<endl;
flag = true;
break;
}
}
//没找到的话给出提示信息
if (!flag) {
cout<<"未找到该运动员或者该运动员没有检录"<<endl;
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ThgWOoGR-1669079859456)(数据结构实验/wps17.jpg)]
E. void selectAthlete()查询运动员
因为所有运动员中最特殊的就是运动员的学号id唯一,所以对运动员查询只能通过查询id来完成,遍历线性表,找到要查询的运动员,通过retrieve()函数把运动员拿出来之后,输出信息。
时间复杂度:O(N)
void selectAthlete() { //查询运动员信息
cout<<"请输入要查询的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;
for (int i = 0; i < athletes.size(); i++) { //遍历整个表 找到指定的运动员
athletes.retrieve(i,temp);
if (temp.getId() == id) {
athletes.remove(i,temp);
//找到了 输出相关信息
cout<<"学号:"<<temp.getId()<<" 姓名:"<<temp.getName()<< " 性别:"<<temp.getSex()<<" 学院:"<<temp.getCollege()
<< " 参加的项目编号:"<<temp.getMatchId()<<" 是否检录:"<<temp.isText1()<<" 参赛成绩:"<<temp.getScore()
<<" 排名:"<<temp.getRank()<<" 获得的分数:"<<temp.getGrade()<<endl;
flag = true;
break;
}
}
//没找到的话给出提示信息
if (!flag) {
cout<<"未找到该运动员"<<endl;
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aajNsLQA-1669079859457)(数据结构实验/wps18.jpg)]
F. void reviceAthlete()修改运动员信息
同理,因为所有运动员中最特殊的就是运动员的学号id唯一,所以修改信息只能通过查询id来完成,遍历线性表,找到要修改的信息的运动员,通过retrieve()函数,先把值拿出来,再通过remove()移除值,再通过insert()进行插入完成修改的操作。
时间复杂度:O(N)
void reviceAthlete(){ //修改运动员信息
cout<<"请输入要修改的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;
int i = 0;
for (; i < athletes.size(); i++) { //找到 指定学号的运动员
athletes.retrieve(i,temp);
if (temp.getId() == id) {
flag = true;
break;
}
}
if (!flag) {
cout<<"未找到该运动员"<<endl;
}else{
cout<<"请选择要修改运动员的那些信息"<<endl;
cout<<"------修改运动员的姓名----1"<<endl;
cout<<"------修改运动员的学号----2"<<endl;
cout<<"------修改运动员的性别----3"<<endl;
cout<<"------修改运动员学院----4"<<endl;
cout<<"------修改运动员参赛项目编号----5"<<endl;
cout<<"运动员的检录,成绩排名,分数,不予修改,请使用上一步的函数操作"<<endl;
cout<<"请输入对应信息的编号"<<endl;
int a;
cin>>a;
switch(a){ //运动员的检录,成绩排名,分数,不予修改
case 1:{
cout<<"请输入新的运动员的姓名:"<<endl;
string name;
cin>>name;
temp.setName(name); //输入新信息
athletes.replace(i,temp);//进行替换
cout<<"运动员的姓名修改成功!"<<endl;
break;
}
case 2:{
cout << "请输入新的运动员的学号:" << endl;
string number;
cin>>number;
temp.setId(number);
athletes.replace(i,temp);
cout << "运动员的学号修改成功!" << endl;
break;
}
case 3:{
cout<<"请输入新的运动员的性别:"<<endl;
string sex;
cin>>sex;
temp.setSex(sex);
athletes.replace(i,temp);
cout<<"运动员的性别修改成功!"<<endl;
break;
}
case 4:{
cout<<"请输入新的学院:"<<endl;
string college;
cin>>college;
temp.setCollege(college);
athletes.replace(i,temp);
cout<<"运动员的学院改成功!"<<endl;
break;
}
case 5:{
cout<<"请输入新的运动员参赛编号:"<<endl;
string matchId;
cin>>matchId;
temp.setMatchId(matchId);
athletes.replace(i,temp);
cout<<"运动员参赛编号修改成功!"<<endl;
break;
}
default: cout<<"输入有误"<<endl;
}
}
}
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aTPlBxU6-1669079859457)(数据结构实验/wps19.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eky1RHAr-1669079859469)(数据结构实验/wps20.jpg)]
(3) .学院
A. void creatColleges()创建学院
利用标准C++ STL库中的vector容器存储学院,遍历运动员表,依次拿出每一个运动员,遍历学院数组,看学院数组中是否存在运动员对应的学院,如果不存在,就创建学院,并且把该运动员信息插入到学院中的运动员信息中,如果有对应的学院,就只把运动员的信息插入到学院的运动员数组中。
时间复杂度:O(N^3)
void creatColleges(List2<Athlete> a) {//创建学院
Athlete temp;
bool flag;//标志1:有没有运动员对应的学院
for (int i = 0; i < a.size(); i++) {//遍历运动员表
flag = false;
a.retrieve(i,temp);
for (auto & college : colleges) { //遍历学院数组
if (college.name == temp.getCollege()) { //如果有和运动员同名的学院
bool flag2 = false;//标志位2:记录运动员是否记录过
for (auto & player : college.athletess) {
if (temp.getId()==player.getId()) flag2 = true;//记录过 标志位为true
}
if (flag2) break;
else{ //运动员还没加在学院的动态数组里面
flag = true;
college.athletess.push_back(temp);//把运动员加在学院的动态数组里面
break;
}
}
}
if (!flag) { //没有学院
flag = true;
College collegeTemp(""+temp.getCollege());//创建学院
collegeTemp.athletess.push_back(temp);//把运动员加在学院里的运动员中
colleges.push_back(collegeTemp);//再把运动员放入数组中
}
}
}
B. void setCollegesScore()设置学院成绩
通过遍历运动员表来创建对应的学院,并且对对应的学院的成绩进行录入。如果是男生,就加入到男生成绩和总成绩;如果是女生,就加入到女生成绩和总成绩。
时间复杂度O(N^2)
void setCollegesScore(vector<College> &colleges){ //设置学院的成绩
for (auto & college : colleges) { //遍历学院vector数组 通过setScore设置成绩
college.setScore();
}
}
void setScore() { //设置成绩
this->score = 0;
this->manScore = 0;
this->womenScore = 0;
for(Athlete temp:athletess){ //遍历运动员表
if (temp.getSex() == "男") { //如果是男同学 就加manScore score
this->manScore += temp.getGrade();
this->score += temp.getGrade();
}else{ //如果是女同学 就加womenScore score
this->womenScore += temp.getGrade();
this->score += temp.getGrade();
}
}
}
C. void sortScore()根据总成绩排序
利用选择排序的思想,以他的综合得分score为关键值来进行排序,每次遍历找出该轮最大值,找到最大的前6个学院,如果小于6个学院,就进行全排。
时间复杂度O(N^2)
void sortScore(vector<College> colleges){ //总成绩排序
int max = 0;
College temp;
//确定排序的轮数 如果不够6个学院的话就全排 6个以上只排前6个
int loop = 6 < colleges.size()? 6 : colleges.size();
for (auto & college : colleges){//防止之前进行过排序 因此对所有的学院都设置为false
college.flag = false;
}
for (int i = 0; i < loop; ++i) {//loop次最大值
max = 0;
for (auto &college: colleges) {
if (college.score > max && !college.flag) {
//每一遍循环里边找到最大的 并把标志位置位true 意思是已经排过序了
college.flag = true;
max = college.score;
temp = college;
}
}
cout << "混合分数第"<<i + 1<<"的是:" << temp.name << " " << temp.score << endl;//显示
}
}
D. void sortManScore()根据男生成绩排序
利用选择排序的思想,以他的男生综合得分manScore为Key值来进行排序,找到最大的前6位。
时间复杂度O(N^2)
void sortManScore(vector<College> colleges){ //男子团体排序
int max = 0;
College temp;
for (auto & college : colleges){//防止之前进行过排序 因此对所有的学院都设置为false
college.flag = false;
}
//确定排序的轮数 如果不够6个学院的话就全排 6个以上只排前6个
int loop = 6 < colleges.size()? 6 : colleges.size();
for (int i = 0; i < loop; ++i) {
max = 0;
for (auto & college : colleges) {
if (college.manScore > max && !college.flag) {
//每一遍循环里边找到最大的 并把标志位置位true 意思是已经排过序了
college.flag = true;
max = college.score;
temp = college;
cout<<temp.name;
}
}
cout << "男子团体分数第"<<i + 1<<"的是:" << temp.name << " " << temp.manScore << endl;//显示
}
}
E. void sortWomenScore()根据女生成绩排队
利用选择排序的思想,以他的女生综合得分womenScore为Key值来进行排序,找到最大的前6位。
时间复杂度O(N^2)
void sortWomenScore(vector<College> colleges){//防止之前进行过排序 因此对所有的学院都设置为false
int max = 0;
College temp;
for (auto & college : colleges){
college.flag = false;
}
//确定排序的轮数 如果不够6个学院的话就全排 6个以上只排前6个
int loop = 6 < colleges.size()? 6 : colleges.size();
for (int i = 0; i < loop; ++i) {
max = 0;
for (auto & college : colleges) {
//每一遍循环里边找到最大的 并把标志位置位true 意思是已经排过序了
if (college.womenScore > max && !college.flag) {
college.flag = true;
max = college.score;
temp = college;
}
}
cout << "女子团体分数第"<<i + 1<<"的是:" << temp.name << " " << temp.womenScore << endl;//显示
}
}
测试:(测试学院的全部操作)
Test.cpp
\#include "E3.h"
int main(){
Match match1("100m",100001,"男","8-31","2:00",20);
Match match2("100m",100001,"女","8-31","2:00",20);
Athlete a("a","2001","男","信控","10001");
Athlete b("b","2002","男","材料","10001");
Athlete c("c","2003","男","信控","10001");
Athlete d("d","2004","男","材料","10001");
Athlete e("e","2005","女","信控","10001");
Athlete f("f","2006","女","材料","10001");
Athlete g("g","2007","女","信控","10001");
Athlete h("h","2008","女","材料","10001");
a.setRank(1);
b.setRank(2);
c.setRank(3);
d.setRank(4);
e.setRank(1);
f.setRank(2);
g.setRank(3);
h.setRank(4);
athletes.insert(0,a);
athletes.insert(1,b);
athletes.insert(2,c);
athletes.insert(3,d);
athletes.insert(4,e);
athletes.insert(5,f);
athletes.insert(6,g);
athletes.insert(7,h);
creatColleges(athletes);
setCollegesScore(colleges);
sortScore(colleges);
sortManScore(colleges);
sortWomenScore(colleges);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e79nMPGW-1669079859470)(数据结构实验/wps21.jpg)]
五.程序源代码
Utility.h
enum Error_code { success, fail, range_errors, underflow, overflow, fatal, not_present, duplicate_error, entry_inserted, entry_found, internal_error };
实验1. 基于单链表实现线性表 List1
Node.h
template <class Node_entry>
struct Node {
//数据域
Node_entry entry;//数值
Node<Node_entry>* next;//next指针
//构造方法
Node();
/*
\* 默认参数
\* 如果不传就用默认参数
\* 如果传了值就用下边的构造方法
\* */
Node(Node_entry item, Node<Node_entry>* add_on = nullptr);
}
Node.cpp
#include "Node.h"
template <class Node_entry> Node<Node_entry>::Node()
{
next = nullptr;
}
template <class Node_entry> Node<Node_entry>::Node(Node_entry item, Node<Node_entry>* add_on)
{
entry = item;
next = add_on;
}
List1.h
\#include "Node.h"
\#include "utility.h"//状态错误
//enum Error_code { success, fail, range_errors, underflow, overflow, fatal, not_present, duplicate_error, entry_inserted, entry_found, internal_error };
template <class List_entry> class List1 {
public:
List1();
int size() const;//大小
bool full() const;//判满
bool empty() const;//判空
void clear();//清空
void traverse(void (*visit)(List_entry &));//通过visit函数指针遍历线性表
Error_code retrieve(int position, List_entry& x) const;//访问position位置的值
Error_code replace(int position, const List_entry& x);//替换position位置的值
Error_code remove(int position, List_entry& x);//移除position位置的值
Error_code insert(int position, const List_entry& x);//在position位置插入一个元素
~List1();//析构
List1(const List1<List_entry>& copy);//拷贝构造
void operator =(const List1<List_entry>& copy);//赋值运算符重载
protected:
//数据域
int count;//计数器
Node<List_entry> *head;//头指针
//辅助方法 找到position位置的节点并返回
Node<List_entry> * set_position(int position) const;
};
List1.cpp
\#include "Node.h"
template<class List_entry> List1<List_entry>::List1() {
//对线性表初始化
count = 0;
head = nullptr;
}
template<class List_entry> List1<List_entry>::~List1() {
//借助clear()方法清空
clear();
}
template<class List_entry> void List1<List_entry>::clear() {
Node<List_entry>* p, * q;
//p 当前节点 q next节点
for (p = head; p; p = q) {
q = p->next;
delete p;
}
count = 0;
head = nullptr;
}
template<class List_entry> int List1<List_entry>::size()const {
return count;
}
template<class List_entry> bool List1<List_entry>::full() const {
return false;
}
template<class List_entry> bool List1<List_entry>::empty()const {
if (head != nullptr) return false;
else return true;
}
template <class List_entry> Node<List_entry>* List1<List_entry>::set_position(int position) const {
Node<List_entry>* q = head;
//遍历position次就来到了position的节点位置
for (int i = 0; i < position; i++) q = q->next;
return q;
}
template <class List_entry> Error_code List1<List_entry>::insert(int position, const List_entry& x) {
if (position < 0 || position > count) //position的位置不合法
return range_errors;
Node<List_entry>* new_node, //新节点
\* previous, //前驱节点
\* following;//后继节点
previous = nullptr;
if (position > 0) { //不是头插
previous = set_position(position - 1);//找到他的前驱节点
following = previous->next;//后继节点
}
else following = head;//是头插的话,没有前驱,后继就是原来的头节点
new_node = new Node<List_entry>(x, following);//借用了node的构造方法 node->next = following
if (new_node == nullptr)
return overflow;
if (position == 0)//如果是头插的话,头节点就是插入的new_node
head = new_node;
else//不是头插的话,就让前驱节点的next指向new_node
previous->next = new_node;
count++;
return success;
}
template <class List_entry> void List1<List_entry>::traverse(void (*visit) (List_entry&)) {
Node<List_entry>* q;
for (q = head; q; q = q->next) { //遍历每一个节点 对每一个节点 通过函数指针来进行操作
(*visit) (q->entry);
}
}
template<class List_entry> Error_code List1<List_entry>::remove(int position, List_entry& x) {
Node<List_entry>* prior,//前驱节点
\* current;//当前节点
if (empty()) return fail;
if (position < 0 || position >= count) return range_errors;//position位置是否合法
if (position > 0) { //删的不是头节点
prior = set_position(position - 1);//前驱
current = prior->next;//当前
prior->next = current->next;//让前驱节点绕过当前节点直接指到后继节点
}
else { //删除头节点
current = head;
head = head->next;
}
x = current->entry;//x带出要删除节点的值
delete current;//通过delete删除节点
count--;
return success;
}
template<class List_entry> Error_code List1<List_entry>::retrieve(int position,List_entry& x) const {
Node<List_entry>* current;
if (position < 0 || position >= count) return range_errors;//position位置是否合法
current = set_position(position);//通过set_position拿到当前节点
x = current->entry;
return success;
}
template<class List_entry> Error_code List1<List_entry>::replace(int position, const List_entry& x) {
Node<List_entry>* current;
if (position < 0 || position >= count) return range_errors;
current = set_position(position);
current->entry = x;
return success;
}
template<class List_entry> List1<List_entry>::List1(const List1<List_entry>& copy) {//拷贝构造
count = copy.count;
Node<List_entry>* new_node, * old_node = copy.head;
if (old_node == nullptr) head = nullptr;
else {
new_node = new Node<List_entry>();
head = new_node;
while (old_node != nullptr) { //遍历拷贝的线性表
old_node = old_node->next;
new_node->next = new Node<List_entry>(old_node->entry);
new_node = new_node->next;//new_node往后拨一个
}
}
}
template<class List_entry>
void List1<List_entry>::operator =(const List1<List_entry>& copy) { //赋值运算符重载
List1 new_copy(copy);//借用拷贝构造
clear();//清空当前表
count = 0;
head = nullptr;
new_copy.count = copy.count;
new_copy.head = head;
}
测试main.cpp
\#include "List1.h"
\#include <iostream>
using namespace std;
// test List1 mechanism
void write_entry(char &c) {
cout << c;
}
int main() {
char x;
List1<char> c_list;
// a list of characters, initialized empty
cout << "List is empty, it has " << c_list.size() << " items.\n";
cout << "Enter characters and the program adds them to the list.\n";
cout << "Use Enter key (newline) to terminate the input.\n";
cout << "When ListSize() is 3, the element will be inserted at the ";
cout << "front of the list.\n The others will appear at the back.\n";
while (!c_list.full() && (x = cin.get()) != '\n')
if (c_list.size() == 3) c_list.insert(0, x);
else c_list.insert(c_list.size(), x);
cout << "The list has " << c_list.size() << " items.\n";
cout << "The function c_list.full(), got " << c_list.full();
if (c_list.full())
cout << " because the list is full.\n";
else cout << " because the list is NOT full.\n";
cout << "c_list.empty(), expecting 0, got " << c_list.empty() << ".\n";
cout << "c_list.traverse(write_entry) output: "; c_list.traverse(write_entry);
cout << "\n"; c_list.clear();
cout << "Cleared the list, printing its contents:\n";
c_list.traverse(write_entry);
cout << "\n"; cout << "Enter characters and the program adds them to the list.\n";
cout << "Use Enter key (newline) to terminate the input.\n";
cout << "When ListSize() is < 3, the element will be inserted at the ";
cout << "front of the list.\n The others will appear at the back.\n";
while (!c_list.full() && (x = cin.get()) != '\n')
if (c_list.size() < 3) c_list.insert(0, x);
else c_list.insert(c_list.size(), x);
c_list.traverse(write_entry);
cout << "\n";
}
实验2. 基于静态链表实现线性表 List2 的典型操作
Node2.h
#include "utility.h"
typedef int index;
const int max_list = 10; // small value for testing purposes
template <class List_entry>
class Node2 {
public:
List_entry entry;//数据
index next;//next 表示数组的下标
};
List2.h
template <class List_entry>
class List2 {
public:
List2();
int size() const;//大小
bool full() const;//判满
bool empty() const;//判空
void clear();//清空
void traverse(void (*visit)(List_entry&));//遍历
Error_code retrieve(int position, List_entry& x) const;//访问position的值,通过x把值带出来
Error_code replace(int position, const List_entry& x);//替换position位置的值设为x
Error_code remove(int position, List_entry& x);//移除position位置的值,用x带出来
Error_code insert(int position, const List_entry& x);//把x插入到position位置
protected:
Node2<List_entry> workspace[max_list];//用数组实现静态链表
index available, //可用空间的表头节点
last_used, //上一次使用的空间 来做标记
head;//头节点
int count;
//辅助方法
index new_node();//创建一个空间
void delete_node(index old_index);//释放空间,连接到available表
int current_position(index n) const;//根据值获取当前的下标
index set_position(int position) const;//根据下标,获得当前的值
};
List2.cpp
template <class List_entry>
index List2<List_entry>::new_node(){
index new_index;
//因为是数组下标 用-1代替nullptr
/*
\* 1. 先看available有没有空间可以用
\* 2. available表没空间了,看能不能新建
\* */
if (available != -1) { //available有空间可以用
new_index = available;//available把头节点给new_node
available = workspace[available].next;//自己跳到下一个节点
}
else if (last_used < max_list - 1) { //available表没有空间可以用 链表的容量没超过最大容量
new_index = ++last_used;//新建
}
else return -1;//如果方式1、2都没有新建成功,返回-1表示失败
workspace[new_index].next = -1;//新节点的next域置空
return new_index;//成功的话 返回新节点
}
template <class List_entry>
void List2<List_entry>::delete_node(index old_index) {
index previous;
if (old_index == head) //删头节点 让head为原来头结点的next
head = workspace[old_index].next;
else { //删除的其他节点
previous = set_position(current_position(old_index) - 1);//通过set_position拿到前驱节点
workspace[previous].next = workspace[old_index].next;//让前驱节点等于待删节点的后继
}
workspace[old_index].next = available;//通过头插的方式把节点添加在available表中
available = old_index;
}
template<class List_entry>
List2<List_entry>::List2()
{
//初始化
//都假定为空 -1
available = -1;
last_used = -1;
head = -1;
count = 0;
}
template<class List_entry>
int List2<List_entry>::size() const{
return count;
}
template<class List_entry>
bool List2<List_entry>::full() const
{
return count > max_list;
}
template<class List_entry>
bool List2<List_entry>::empty() const {
return count == 0;
}
template <class List_entry>
void List2<List_entry>::traverse(void (*visit)(List_entry&)) {
//遍历链表
for (index n = head; n != -1; n = workspace[n].next)//n != -1 n != nullptr
(*visit)(workspace[n].entry);
}
template <class List_entry>
Error_code List2<List_entry>::insert(int position, const List_entry& x) {
index new_index, previous, following;
//判断position位置是否合法
if (position < 0 || position > count) return range_errors;
//不是头插
if (position > 0) {
//找到前驱节点 和 后继节点
previous = set_position(position - 1);
following = workspace[previous].next;
}
//头插 后继就是头节点
else following = head;
if ((new_index = new_node()) == -1) return overflow;//新建节点
workspace[new_index].entry = x;
workspace[new_index].next = following;//next域为他的后继
if (position == 0) //如果是头插 新的头节点就是new_node
head = new_index;
else //不是头插的话 处理他的前驱节点
workspace[previous].next = new_index;
count++;
return success;
}
template <class List_entry>
index List2<List_entry>::set_position(int position) const { //根据下标,获得当前的值
//Node2<List_entry> p;
int i = 0;
int cnt = 0;
if (!(position<0 || position>max_list)) {
//遍历position次 拿到position的节点
for (i = head; cnt < position; cnt++, i = workspace[i].next);
}
return i;
}
template<class List_entry>
int List2<List_entry>::current_position(index n) const { //根据节点 来获取下标
int cnt = 0;
for (int i = head; i != n; cnt++, i = workspace[i].next);
return cnt;
}
template<class List_entry>
Error_code List2<List_entry>::retrieve(int position, List_entry& x) const { //访问position位置的值,通过x带出来
if (position < 0 || position > count) return range_errors;//判断position位置合不合法
int cnt = 0, i;
for (i = head; cnt != position; cnt++, i = workspace[i].next);//遍历的方式找到position位置
x = workspace[i].entry;
return success;
}
template<class List_entry>
Error_code List2<List_entry>::remove(int position, List_entry& x) { //析出position位置的节点
x = workspace[set_position(position)].entry;//set_position找到节点
delete_node(set_position(position));//set_position找到节点 delete_node进行删除
count--;
return success;
}
template<class List_entry>
void List2<List_entry>::clear()
{
index p, q;
for (p = head; p != -1; p = workspace[p].next) { //遍历链表 对每一个节点进行delete_node
q = p;
delete_node(p);
}
count = 0;
head = -1;
}
template<class List_entry>
Error_code List2<List_entry>::replace(int position, const List_entry &x) {
if (position < 0 || position > count) return range_errors;//判断下标合不合法
workspace[set_position(position)].entry = x;//set_position找到position位置的节点 替换值
return success;
}
Main.cpp
\#include "List2.h"
\#include <iostream>
using namespace std;
// test List2 mechanism
void write_entry(char &c) {
cout << c;
}
int main() {
char x;
List2<char> c_list;
// a list of characters, initialized empty
cout << "List is empty, it has " << c_list.size() << " items.\n";
cout << "Enter characters and the program adds them to the list.\n";
cout << "Use Enter key (newline) to terminate the input.\n";
cout << "When ListSize() is 3, the element will be inserted at the ";
cout << "front of the list.\n The others will appear at the back.\n";
while (!c_list.full() && (x = cin.get()) != '\n')
if (c_list.size() == 3) c_list.insert(0, x);
else c_list.insert(c_list.size(), x);
cout << "The list has " << c_list.size() << " items.\n";
cout << "The function c_list.full(), got " << c_list.full();
if (c_list.full())
cout << " because the list is full.\n";
else cout << " because the list is NOT full.\n";
cout << "c_list.empty(), expecting 0, got " << c_list.empty() << ".\n";
cout << "c_list.traverse(write_entry) output: "; c_list.traverse(write_entry);
cout << "\n"; c_list.clear();
cout << "Cleared the list, printing its contents:\n";
c_list.traverse(write_entry);
cout << "\n"; cout << "Enter characters and the program adds them to the list.\n";
cout << "Use Enter key (newline) to terminate the input.\n";
cout << "When ListSize() is < 3, the element will be inserted at the ";
cout << "front of the list.\n The others will appear at the back.\n";
while (!c_list.full() && (x = cin.get()) != '\n')
if (c_list.size() < 3) c_list.insert(0, x);
else c_list.insert(c_list.size(), x);
c_list.traverse(write_entry);
cout << "\n";
}
实验3. 基于线性表 List1、线性表 List2 实现线性表的应用:运动会信息管理
E3.h(包含所需要的3个类和相关的函数)
//
// Created by huangruidong on 2022/6/19.
//
\#ifndef NEWDATASTRUCT_E3_H
\#define NEWDATASTRUCT_E3_H
\#include<iostream>
\#include<fstream>
\#include "vector"
\#include "List1.h"
\#include "List2.h"
\#include<string>
using namespace std;
class Match
{
public:
string call; //比赛项目名称
int number; //比赛项目编号
string sex; //比赛性别
string date;//比赛的日期
string time;//比赛时间
int num;//人数
public:
//无参构造
Match(){};
//有参构造
Match(const string &call, int number, const string &sex, const string &date, const string &time, int num) : call(
call), number(number), sex(sex), date(date), time(time), num(num) {};
//get set方法
const string &getCall() const {
return call;
}
void setCall(const string &call) {
Match::call = call;
}
int getNumber() const {
return number;
}
void setNumber(int number) {
Match::number = number;
}
const string &getSex() const {
return sex;
}
void setSex(const string &sex) {
Match::sex = sex;
}
const string &getDate() const {
return date;
}
void setDate(const string &date) {
Match::date = date;
}
const string &getTime() const {
return time;
}
void setTime(const string &time) {
Match::time = time;
}
int getNum() const {
return num;
}
void setNum(int num) {
Match::num = num;
}
//赋值运算符重载
Match operator = (const Match& copy) {
call = copy.call;
number = copy.number;
sex = copy.sex;
date = copy.date;
time = copy.time;
num = copy.num;
return *this;
}
};
List1<Match> matchs;//用List1存储比赛项目
int size = 0;
void setMatch() //新建项目
{ ofstream fout("D:\\比赛项目.txt",ios::app);
char ch;
do
{ cout<<"请分别输入比赛项目名称、编号(假设为 6 位数字)、参与该项目的运动员性别、比赛 日期、比赛时间、比赛人数."<<endl;
string call;
int number;
string sex;
string date;
string time;
int num;
cin>>call>>number>>sex>>date>>time>>num;//输入相关属性
Match temp = Match(call,number,sex,date,time,num);//创建一个temp临时变量
matchs.insert(0,temp);//头插在链表中
fout.write((char *)&temp,sizeof(Match));//写入文件流
cout<<"是否继续输入,如果继续键入Y|y"<<endl;
cin>>ch;
}while(ch=='y'||ch=='Y');
fout.close();
}
void changeMatch() //修改一个项目
{
cout<<"您正在进行修改比赛项目有关事项操作!"<<endl;
cout<<"请输入要修改比赛项目的编号:"<<endl;
int number1; //要修改的比赛项目编号
int sign=0; //设置的标记变量
cin>>number1;
int i = 0;
for (; i < matchs.size(); i++) { //遍历表 找指定的项目编号
Match temp;
matchs.retrieve(i,temp);
if (number1 == temp.getNumber()){
sign = 1;
break;
}
}
//没找到的话 输出信息提示
if (sign==0)
cout<<"没有找到要修改的记录!"<<endl;
else //找到了项目
{
cout<<"请选择要修改比赛项目的那些信息"<<endl;
cout<<"------修改比赛项目的名称----1"<<endl;
cout<<"------修改比赛项目的编号----2"<<endl;
cout<<"------修改比赛项目的性别----3"<<endl;
cout<<"------修改比赛日期----4"<<endl;
cout<<"------修改比赛时间----5"<<endl;
cout<<"------修改比赛人数----6"<<endl;
cout<<"请输入对应信息的编号"<<endl;
int a;
cin>>a;
switch(a) //switch case 控制修改的那一部分
{
case 1:{
cout<<"请输入新的比赛项目名称:"<<endl;
string name;
cin>>name;
Match temp;
matchs.retrieve(i,temp);//通过上次标记的i 拿出来找到的项目
temp.setCall(name);//修改项目姓名
matchs.replace(i,temp);//对表中的数据进行替换
cout<<"比赛项目名称修改成功!"<<endl;
break;
}
case 2:{
cout << "请输入新的比赛编号:" << endl;
int number;
cin>>number;
Match match;
matchs.remove(i,match);
match.setNumber(number);
matchs.insert(i,match);
cout << "比赛项目编号修改成功!" << endl;
break;
}
case 3:{
cout<<"请输入新的参赛选手性别:"<<endl;
string sex;
cin>>sex;
Match match;
matchs.remove(i,match);
match.setSex(sex);
matchs.insert(i,match);
cout<<"参赛选手性别修改成功!"<<endl;
break;
}
case 4:{
cout<<"请输入新的日期:"<<endl;
string date;
cin>>date;
Match match;
matchs.remove(i,match);
match.setDate(date);
matchs.insert(i,match);
cout<<"比赛日期修改成功!"<<endl;
break;
}
case 5:{
cout<<"请输入新的比赛时间:"<<endl;
string time;
cin>>time;
Match match;
matchs.remove(i,match);
match.setDate(time);
matchs.insert(i,match);
cout<<"比赛时间修改成功!"<<endl;
break;
}
case 6:{
cout<<"请输入新的参赛人数:"<<endl;
int num;
cin>>num;
Match match;
matchs.remove(i,match);
match.setNum(num);
matchs.insert(i,match);
cout<<"参赛人数修改成功!"<<endl;
break;
}
}
}
}
void deleteMatch() //删除一个项目
{
cout<<"------根据比赛项目的编号删除----1"<<endl;
cout<<"------根据比赛项目的名称删除----2"<<endl;
int n;
cin>>n;
switch(n) {
case 1: {
cout << "请输入要删除的比赛编号" << endl;
int number;
cin >> number;
Match temp;
int i = 0;
bool isFind = false;//标记
for (; i < matchs.size(); i++) { //遍历整个表 如果找到 就通过remove进行删除
matchs.retrieve(i, temp);
if (temp.getNumber() == number) {
cout << "找到信息" << endl;
matchs.remove(i, temp);
cout << "删除成功" << endl;
isFind = true;
}
}
//没找到的话 输出信息提示
if (!isFind) cout << "未找到该项目" << endl;
break;
}
case 2: {
cout << "请输入要删除的比赛名称" << endl;
string name;
cin >> name;
Match temp;
int i = 0;
bool isFind = false;
for (; i < matchs.size(); i++) {
matchs.retrieve(i, temp);
if (temp.getCall() == name) {
cout << "找到信息" << endl;
matchs.remove(i, temp);
cout << "删除成功" << endl;
isFind = true;
}
}
//没找到的话 输出信息提示
if (!isFind) cout << "未找到该项目" << endl;
break;
}
}
}
void selectMatch() //查询一个项目
{
cout<<"------根据比赛项目的编号查找----1"<<endl;
cout<<"------根据比赛项目的名称查找----2"<<endl;
int n;
cin>>n;
switch(n) {
case 1: {
cout << "请输入要查找的比赛编号" << endl;
int number;
cin >> number;
Match temp;
int i = 0;
bool isFind = false;//标志位
for (; i < matchs.size(); i++) { //遍历整张表 如果找到 让标志位设为true
matchs.retrieve(i, temp);
if (temp.getNumber() == number) { //找到信息的话 就把相关的信息进行输出
cout << "找到信息:" << endl;
cout<<temp.getNumber()<<" " <<temp.getCall()<<" "<<temp.getSex()<<" "<<temp.getDate()<<" "<<temp.getTime()<<" "<<temp.getNum()<<endl;
isFind = true;
}
}
//没找到的话 输出信息提示
if (!isFind) cout << "未找到该项目" << endl;
break;
}
case 2: {
cout << "请输入要删除的比赛名称" << endl;
string name;
cin >> name;
Match temp;
int i = 0;
bool isFind = false;
for (; i < matchs.size(); i++) {
matchs.retrieve(i, temp);
if (temp.getCall() == name) {
cout << "找到信息:" << endl;
cout<<temp.getNumber()<<" " <<temp.getCall()<<" "<<temp.getSex()<<" "<<temp.getDate()<<" "<<temp.getTime()<<" "<<temp.getNum()<<endl;
isFind = true;
}
}
if (!isFind) cout << "未找到该项目" << endl;
break;
}
}
}
class Athlete
{
private:
string name;//姓名
string id;//学号
string sex;//性别
string college;//学院
string matchId;//参加的比赛编号
private:
//项目编号
bool isText;//是否检录
string score;//参赛成绩
int rank;//排名
int grade;//级别分数
public:
//有参构造
Athlete( string &name, string &id, string &sex, string &college, string &matchId,
bool isText, string &score, int rank, int grade) : name(name), id(id), sex(sex), college(college),
matchId(matchId), isText(isText), score(score),
rank(rank), grade(grade) {};
//赋值运算符重载
Athlete operator = (const Athlete& copy){
name = copy.name;
id = copy.id;
sex = copy.sex;
college = copy.college;
matchId = copy.matchId;
isText = copy.isText;
score = copy.score;
rank = copy.rank;
grade = copy.grade;
return *this;
}
//重写的有参构造
Athlete(const string &name, const string &id, const string &sex, const string &college, const string &matchId)
: name(name), id(id), sex(sex), college(college), matchId(matchId) {};
//拷贝构造
Athlete(Athlete const &a2) {
this->name = a2.name;
this->id = a2.id;
this->sex = a2.sex;
this->college = a2.college;
this->isText = a2.isText;
this->score = a2.score;
this->rank = a2.rank;
this->grade = a2.grade;
}
//get set方法
const string &getName() const {
return name;
}
void setName(const string &name) {
Athlete::name = name;
}
const string &getId() const {
return id;
}
void setId(const string &id) {
Athlete::id = id;
}
const string &getSex() const {
return sex;
}
void setSex(const string &sex) {
Athlete::sex = sex;
}
const string &getCollege() const {
return college;
}
void setCollege(const string &college) {
Athlete::college = college;
}
const string &getMatchId() const {
return matchId;
}
void setMatchId(const string &matchId) {
Athlete::matchId = matchId;
}
bool isText1() const {
return isText;
}
void setIsText(bool isText) {
Athlete::isText = isText;
}
string getScore() const {
return score;
}
void setScore(string score) {
this->score = ""+score;
}
int getRank() const {
return rank;
}
//计算分数
//rank 获得几等奖 对应的分数grade就是多少
void setRank(int rank) {
this->rank = rank;
if (rank == 1) this->grade = 3;
else if (rank == 2) this->grade = 2;
else if (rank == 3) this->grade = 1;
else this->grade = 0;
}
int getGrade() const {
return grade;
}
//无参构造
Athlete() {}
Athlete(const Node2<struct Athlete> node2);
};
//静态链表实现的线性表存储运动员
List2<Athlete> athletes;
void inputAthlete()//创建运动员
{ ofstream fout("d:\\运动员.txt",ios::app);//打开文件
int i = 0;
char ch;
do
{ cout<<"请分别输入运动员姓名,学号,性别,学院,参加的项目标号"<<endl;
string name;
string id;
string sex;
string college;
string matchId;
cin>>name>>id>>sex>>college>>matchId;//输入相关信息
Athlete temp(name,id,sex,college,matchId);//创建temp对象
athletes.insert(i,temp);//插入到线性表中
fout.write((char *)&temp,sizeof(Athlete));//写入文件
cout<<"是否继续输入,如果继续键入Y|y"<<endl;
cin>>ch;
}while(ch=='y'||ch=='Y');
fout.close();
}
void deleteAthlete()//撤销报名 (删除运动员)
{
//只有学号是唯一的,所以根据学号来撤销报名
cout<<"请输入被撤销报名的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;//标志位
for (int i = 0; i < athletes.size(); i++) { //遍历表 来寻找
athletes.retrieve(i,temp);
if (temp.getId() == id) {//找到 通过remove移除
athletes.remove(i,temp);
cout<<"删除成功"<<endl;
flag = true;
break;
}
}
//未找到运动员 输出信息进行提示
if (!flag) {
cout<<"未找到该运动员"<<endl;
}
}
void cheekAthlete(){//对运动员检录
cout<<"请输入要检录的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;
for (int i = 0; i < athletes.size(); i++) {//遍历线性表
athletes.retrieve(i,temp);
if (temp.getId() == id) { //如果找到了
if (temp.isText1()) { //先看有没有检录过
cout<<"已经检录过了"<<endl;
flag = true;
break;
}else{ //没检录过 检录 replace替换表的数据
temp.setIsText(true);
athletes.replace(i,temp);
cout<<"检录成功"<<endl;
flag = true;
break;
}
}
}
//没找到的话给出提示信息
if (!flag) {
cout<<"未找到该运动员"<<endl;
}
}
void loginScoreAthlete(){//等级运动员的信息
cout<<"请输入要录入分数的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
cout<<"请输入该运动员的成绩 和 排名"<<endl;
string score;
int rank;
cin>>score;//成绩
cin>>rank;//排名
bool flag =false;
for (int i = 0; i < athletes.size(); i++) { //遍历整个表 找到要登记成绩的学生
athletes.retrieve(i,temp);
if (temp.getId() == id && temp.isText1()) {//如果id查到,并且检录过了
temp.setScore(score);
temp.setRank(rank);//登记信息
athletes.replace(i,temp);//替换表中的数据
cout<<"成绩录入完成"<<endl;
flag = true;
break;
}
}
//没找到的话给出提示信息
if (!flag) {
cout<<"未找到该运动员或者该运动员没有检录"<<endl;
}
}
void selectAthlete() { //查询运动员信息
cout<<"请输入要查询的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;
for (int i = 0; i < athletes.size(); i++) { //遍历整个表 找到指定的运动员
athletes.retrieve(i,temp);
if (temp.getId() == id) {
//找到了 输出相关信息
cout<<"学号:"<<temp.getId()<<" 姓名:"<<temp.getName()<< " 性别:"<<temp.getSex()<<" 学院:"<<temp.getCollege()
<< " 参加的项目编号:"<<temp.getMatchId()<<" 是否检录:"<<temp.isText1()<<" 参赛成绩:"<<temp.getScore()
<<" 排名:"<<temp.getRank()<<" 获得的分数:"<<temp.getGrade()<<endl;
flag = true;
break;
}
}
//没找到的话给出提示信息
if (!flag) {
cout<<"未找到该运动员"<<endl;
}
}
void reviceAthlete(){ //修改运动员信息
cout<<"请输入要修改的运动员的学号"<<endl;
string id;
cin>>id;
Athlete temp;
bool flag =false;
int i = 0;
for (; i < athletes.size(); i++) { //找到 指定学号的运动员
athletes.retrieve(i,temp);
if (temp.getId() == id) {
flag = true;
break;
}
}
if (!flag) {
cout<<"未找到该运动员"<<endl;
}else{
cout<<"请选择要修改运动员的那些信息"<<endl;
cout<<"------修改运动员的姓名----1"<<endl;
cout<<"------修改运动员的学号----2"<<endl;
cout<<"------修改运动员的性别----3"<<endl;
cout<<"------修改运动员学院----4"<<endl;
cout<<"------修改运动员参赛项目编号----5"<<endl;
cout<<"运动员的检录,成绩排名,分数,不予修改,请使用上一步的函数操作"<<endl;
cout<<"请输入对应信息的编号"<<endl;
int a;
cin>>a;
switch(a){ //运动员的检录,成绩排名,分数,不予修改
case 1:{
cout<<"请输入新的运动员的姓名:"<<endl;
string name;
cin>>name;
temp.setName(name); //输入新信息
athletes.replace(i,temp);//进行替换
cout<<"运动员的姓名修改成功!"<<endl;
break;
}
case 2:{
cout << "请输入新的运动员的学号:" << endl;
string number;
cin>>number;
temp.setId(number);
athletes.replace(i,temp);
cout << "运动员的学号修改成功!" << endl;
break;
}
case 3:{
cout<<"请输入新的运动员的性别:"<<endl;
string sex;
cin>>sex;
temp.setSex(sex);
athletes.replace(i,temp);
cout<<"运动员的性别修改成功!"<<endl;
break;
}
case 4:{
cout<<"请输入新的学院:"<<endl;
string college;
cin>>college;
temp.setCollege(college);
athletes.replace(i,temp);
cout<<"运动员的学院改成功!"<<endl;
break;
}
case 5:{
cout<<"请输入新的运动员参赛编号:"<<endl;
string matchId;
cin>>matchId;
temp.setMatchId(matchId);
athletes.replace(i,temp);
cout<<"运动员参赛编号修改成功!"<<endl;
break;
}
default: cout<<"输入有误"<<endl;
}
}
}
class College
{
public:
College() { //无参构造
}
College operator=(const College& college) { //赋值运算符重载
name = college.name;
athletess = college.athletess;
manScore = college.manScore;
womenScore = college.womenScore;
score = college.score;
return *this;
}
College(College const &college) { // 拷贝构造
name = college.name;
athletess = college.athletess;
manScore = college.manScore;
womenScore = college.womenScore;
score = college.score;
}
string name;//学院名称
vector<Athlete> athletess;//数组vector 运动员
int manScore;//男子得分
int womenScore;//女子得分
int score;//混合得分
public:
bool flag;//标志位 这个学院有没有排过序
College(string name) { // 重写的构造函数
flag = false;
this->name = name;
}
void setScore() { //设置成绩
this->score = 0;
this->manScore = 0;
this->womenScore = 0;
for(Athlete temp:athletess){ //遍历运动员表
if (temp.getSex() == "男") { //如果是男同学 就加manScore score
this->manScore += temp.getGrade();
this->score += temp.getGrade();
}else{ //如果是女同学 就加womenScore score
this->womenScore += temp.getGrade();
this->score += temp.getGrade();
}
}
}
};
//利用STL的vector来存储学院 易操作
vector<College> colleges ;
void creatColleges(List2<Athlete> a) {//创建学院
Athlete temp;
bool flag;//标志1:有没有运动员对应的学院
for (int i = 0; i < a.size(); i++) {//遍历运动员表
flag = false;
a.retrieve(i,temp);
for (auto & college : colleges) { //遍历学院数组
if (college.name == temp.getCollege()) { //如果有和运动员同名的学院
bool flag2 = false;//标志位2:记录运动员是否记录过
for (auto & player : college.athletess) {
if (temp.getId()==player.getId()) flag2 = true;//记录过 标志位为true
}
if (flag2) break;
else{ //运动员还没加在学院的动态数组里面
flag = true;
college.athletess.push_back(temp);//把运动员加在学院的动态数组里面
break;
}
}
}
if (!flag) { //没有学院
flag = true;
College collegeTemp(""+temp.getCollege());//创建学院
collegeTemp.athletess.push_back(temp);//把运动员加在学院里的运动员中
colleges.push_back(collegeTemp);//再把运动员放入数组中
}
}
}
void setCollegesScore(vector<College> &colleges){ //设置学院的成绩
for (auto & college : colleges) { //遍历学院vector数组 通过setScore设置成绩
college.setScore();
}
}
void sortScore(vector<College> colleges){ //总成绩排序
int max = 0;
College temp;
//确定排序的轮数 如果不够6个学院的话就全排 6个以上只排前6个
int loop = 6 < colleges.size()? 6 : colleges.size();
for (auto & college : colleges){//防止之前进行过排序 因此对所有的学院都设置为false
college.flag = false;
}
for (int i = 0; i < loop; ++i) {//loop次最大值
max = 0;
for (auto &college: colleges) {
if (college.score > max && !college.flag) {
//每一遍循环里边找到最大的 并把标志位置位true 意思是已经排过序了
college.flag = true;
max = college.score;
temp = college;
}
}
cout << "混合分数第"<<i + 1<<"的是:" << temp.name << " " << temp.score << endl;//显示
}
}
void sortManScore(vector<College> colleges){ //男子团体排序
int max = 0;
College temp;
for (auto & college : colleges){//防止之前进行过排序 因此对所有的学院都设置为false
college.flag = false;
}
//确定排序的轮数 如果不够6个学院的话就全排 6个以上只排前6个
int loop = 6 < colleges.size()? 6 : colleges.size();
for (int i = 0; i < loop; ++i) {
max = 0;
for (auto & college : colleges) {
if (college.manScore > max && !college.flag) {
//每一遍循环里边找到最大的 并把标志位置位true 意思是已经排过序了
college.flag = true;
max = college.score;
temp = college;
cout<<temp.name;
}
}
cout << "男子团体分数第"<<i + 1<<"的是:" << temp.name << " " << temp.manScore << endl;//显示
}
}
void sortWomenScore(vector<College> colleges){//防止之前进行过排序 因此对所有的学院都设置为false
int max = 0;
College temp;
for (auto & college : colleges){
college.flag = false;
}
//确定排序的轮数 如果不够6个学院的话就全排 6个以上只排前6个
int loop = 6 < colleges.size()? 6 : colleges.size();
for (int i = 0; i < loop; ++i) {
max = 0;
for (auto & college : colleges) {
//每一遍循环里边找到最大的 并把标志位置位true 意思是已经排过序了
if (college.womenScore > max && !college.flag) {
college.flag = true;
max = college.score;
temp = college;
}
}
cout << "女子团体分数第"<<i + 1<<"的是:" << temp.name << " " << temp.womenScore << endl;//显示
}
}
void menu1()//运动会项目管理菜单
{ cout<<"******************************"<<endl;
cout<<endl;
cout<<"******学校运动会管理系统******"<<endl;
cout <<"------运动会项目管理--------" << endl;
cout<<"----创建项目 请按:1----"<<endl;
cout<<"----数据修改 请按:2----"<<endl;
cout<<"----数据删除 请按:3----"<<endl;
cout<<"----数据查询 请按:4----"<<endl;
cout<<"----返回主菜单 请按:0----"<<endl;
cout<<endl;
cout<<"*******************************"<<endl;
cout<<endl;
cout<<"*****请输入一个数据进行选择!*****"<<endl;
int num;
cin>>num;
switch (num) {
case 1:{
setMatch();
break;
}
case 2:{
changeMatch();
break;
}
case 3:{
deleteMatch();
break;
}
case 4:{
selectMatch();
break;
}
case 0:{
break;
}
default:cout<<"输入有误"<<endl;
}
}
void menu2()//运动员管理菜单
{
cout<<"******************************"<<endl;
cout<<endl;
cout<<"******学校运动会管理系统******"<<endl;
cout <<"------运动会运动员管理--------" << endl;
cout<<"----创建运动员 请按:1----"<<endl;
cout<<"----撤销报名 请按:2----"<<endl;
cout<<"----赛事检录 请按:3----"<<endl;
cout<<"----成绩录入 请按:4----"<<endl;
cout<<"----信息查询 请按:5----"<<endl;
cout<<"----信息修改 请按:6----"<<endl;
cout<<"----返回主菜单 请按:0----"<<endl;
cout<<endl;
cout<<"*******************************"<<endl;
cout<<endl;
cout<<"*****请输入一个数据,并按回车键!*****"<<endl;
int num;
cin>>num;
switch (num) {
case 1:{
inputAthlete();
break;
}
case 2:{
deleteAthlete();
break;
}
case 3:{
cheekAthlete();
break;
}
case 4:{
loginScoreAthlete();
break;
}
case 5:{
selectAthlete();
break;
}
case 6:{
reviceAthlete();
break;
}
case 0: break;
default:cout<<"输入有误"<<endl;
}
}
void menu3() {//学院管理菜单
cout<<"******************************"<<endl;
cout<<endl;
cout<<"******学校运动会管理系统******"<<endl;
cout <<"------学院项目管理--------" << endl;
cout<<"----混合团体前6名学院 请按:1----"<<endl;
cout<<"----男子团体前6名学院 请按:2----"<<endl;
cout<<"----女子团体前6名学院 请按:3----"<<endl;
cout<<"----返回主菜单 请按:0----"<<endl;
cout<<endl;
cout<<"*******************************"<<endl;
cout<<endl;
cout<<"*****请输入一个数据,并按回车键!*****"<<endl;
int num;
cin>>num;
creatColleges(athletes);
setCollegesScore(colleges);
switch (num) {
case 1:{
sortScore(colleges);
break;
}
case 2:{
sortManScore(colleges);
break;
}
case 3:{
sortWomenScore(colleges);
break;
}
case 0: break;
}
}
void menu() {//主菜单
while(true) {
cout << "******************************" << endl;
cout << endl;
cout << "******学校运动会管理系统******" << endl;
cout << "----运动会项目管理 请按:1----" << endl;
cout << "----运动员管理 请按:2----" << endl;
cout << "----学院管理 请按:3----" << endl;
cout << "----退出系统 请按:0----" << endl;
cout << endl;
cout << "*******************************" << endl;
cout << endl;
cout << "*****请输入一个数据,并按回车键!*****" << endl;
int num;
cin>>num;
switch (num) {
case 1:{//运动会项目菜单
menu1();
break;
}
case 2:{//运动员管理菜单
menu2();
break;
}
case 3:{//学院管理菜单
menu3();
break;
}
case 0:
return;
}
}
}
\#endif //NEWDATASTRUCT_E3_H
Test.cpp
//
// Created by huangruidong on 2022/5/9.
//
\#include "queue"
\#include "E3.h"
using namespace std;
//int main(){
// Athlete athlete("zs","2005010112","男","xk","1");
// athlete.setRank(1);
// athletes.insert(0,athlete);
// creatColleges(athletes);
// setCollegesScore(colleges);
// cout<<colleges[0].score;
// sortScore(colleges);
// //Athlete(const string &name, const string &id, const string &sex, const string &college, const string &matchId)
// // : name(name), id(id), sex(sex), college(college), matchId(matchId) {};
//}
//int main(){
// Match match("100m",10001,"男","8-31","2:00",20);
// Match match2("200m",10002,"男","8-31","2:00",20);
// matchs.insert(0,match);
// matchs.insert(1,match2);
// changeMatch();
// cout<<match.getCall()<<endl;
//}
//int main(){
// Athlete athlete("zs","2005010112","男","xk","1");
// athletes.insert(0,athlete);
// reviceAthlete();
//}
\#include "E3.h"
int main(){
Match match1("100m",100001,"男","8-31","2:00",20);
Match match2("100m",100001,"女","8-31","2:00",20);
Athlete a("a","2001","男","信控","10001");
Athlete b("b","2002","男","材料","10001");
Athlete c("c","2003","男","信控","10001");
Athlete d("d","2004","男","材料","10001");
Athlete e("e","2005","女","信控","10001");
Athlete f("f","2006","女","材料","10001");
Athlete g("g","2007","女","信控","10001");
Athlete h("h","2008","女","材料","10001");
a.setRank(1);
b.setRank(2);
c.setRank(3);
d.setRank(4);
e.setRank(1);
f.setRank(2);
g.setRank(3);
h.setRank(4);
athletes.insert(0,a);
athletes.insert(1,b);
athletes.insert(2,c);
athletes.insert(3,d);
athletes.insert(4,e);
athletes.insert(5,f);
athletes.insert(6,g);
athletes.insert(7,h);
creatColleges(athletes);
setCollegesScore(colleges);
sortScore(colleges);
sortManScore(colleges);
sortWomenScore(colleges);
}
Main.cpp
\#include "queue"
\#include "E3.h"
using namespace std;
int main() {
menu();
return 0;
}
六.实验数据、结果分析
- 基于单链表实现线性表 List1
Main.cpp测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMZlgBvD-1669079859471)(数据结构实验/wps22.jpg)]
结果分析:实验按任务书的要求完成,测试功能正确无误,时间复杂度的估计在设计时已经给出,实验结果稳定。
- 基于静态链表实现线性表 List2 的典型操作
Main.cpp测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W3VZBHpS-1669079859472)(数据结构实验/wps23.jpg)]
结果分析:实验按任务书的要求完成,测试功能正确无误,时间复杂度的估计在设计时已经给出,实验结果稳定。
- 实验3. 基于线性表 List1、线性表 List2 实现线性表的应用:运动会信息管理
具体的测试在问题的分解中已经测试过了。
通过文件流的来把信息保存在磁盘中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJ3ERZcG-1669079859473)(数据结构实验/wps24.jpg)]
如上图所示,但是存在一些问题:
字符编码加载错误:
比赛项目.dat
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qr8Te7QL-1669079859473)(数据结构实验/wps25.jpg)]
运动员.dat
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cZ46INoE-1669079859474)(数据结构实验/wps26.jpg)]
认为是字符编码问题导致
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HHrV7Djb-1669079859474)(数据结构实验/wps27.jpg)]
尝试所有编码,没有解决问题。可能是clion配置的字符为utf-8代替GBK导致的输出的文件编码问题。
Clion设置如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-59UtXhib-1669079859475)(数据结构实验/wps28.jpg)]
七.存在的问题与体会
-
在数据结构的设计中,模板的使用和创建尤为重要,而且较难掌握,在编写后续操作中,需要不断地对模板进行调整。
-
设计实现数据结构,首先清除这种数据结构的特点是什么,了解要用什么的方式来实现这种数据结构。
-
过程中出现了好多的细节错误,导致进度缓慢,使用了大量时间调试,例如:赋值运算
符重载,深浅拷贝构造的问题,函数传参时传的形参,而不能改变实体等等。
- 该实验使用的环境是Clion配置的MinGW,对实验中遇到的各种问不断地修正调试,加强了对这款编译器的熟练度。
- 实验中存在的问题是,把数据写入到文件中字符编码异常,尝试修改,未成功,应该是clion的配置存在问题。
- 掌握了通过单链表和静态链表来实现线性表,对单链表和静态链表更加熟悉,在实验三中又锻炼了线性表的使用。
- 理解了好多编程过程的小细节,const,常引用,引用,指针,delete等许多细节。