数据结构实验

欢迎大家访问我的博客,www.huangrd.top学习更多内容。


title: 数据结构实验
date: 2022-11-22 09:15:30
categories:

  • 算法
    tags:
  • 算法
  • 数据结构
  • 实验

数据结构实验

线性表的应用

一.实验目的

  1. 掌握线性表的单链表实现与静态链表实现。

  2. 掌握线性表的应用:运动会信息管理系统。

二. 实验要求、内容

  1. 基于单链表实现线性表 List1 的典型操作(判空、判满、求表长、插入、删除、查找、修改、遍历、置空、普

通构造、拷贝构造、赋值运算符重载、析构),编写简单程序使用该线性表,测试和调试程序。

  1. 基于静态链表实现线性表 List2 的典型操作(判空、判满、求表长、插入、删除、查找、修改、遍历、置空、

普通构造),编写简单程序使用该线性表,测试和调试程序。

  1. 基于线性表 List1、线性表 List2 实现线性表的应用:运动会信息管理,测试和调试程序。

  2. 按要求撰写实验报告、录制程序运行以及讲解程序的视频。报告中要包含算法性能的讨论以及根据实现效率

在问题的多种解决方案中进行比较、选择的说明。

三.实验设备

计算机、Windows 操作系统、C++语言集成开发环境。

四.实验原理(或程序框图)及步骤

*实验1*

1.问题分解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6j2ME2nd-1669079859446)(数据结构实验/wps2.jpg)]

链表中每个节点包含 1 个数据域(entry)和 1 个指针域(next),指向下一个节点。采用模板完成节点的定义。

  1. 对问题一基于单链表实现线性表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)]

创建三个类的线性表进行操作,通过目录连接起来。

  1. 基于线性表 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;
}

六.实验数据、结果分析

  1. 基于单链表实现线性表 List1

Main.cpp测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMZlgBvD-1669079859471)(数据结构实验/wps22.jpg)]

结果分析:实验按任务书的要求完成,测试功能正确无误,时间复杂度的估计在设计时已经给出,实验结果稳定。

  1. 基于静态链表实现线性表 List2 的典型操作

Main.cpp测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W3VZBHpS-1669079859472)(数据结构实验/wps23.jpg)]

结果分析:实验按任务书的要求完成,测试功能正确无误,时间复杂度的估计在设计时已经给出,实验结果稳定。

  1. 实验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)]

七.存在的问题与体会

  1. 在数据结构的设计中,模板的使用和创建尤为重要,而且较难掌握,在编写后续操作中,需要不断地对模板进行调整。

  2. 设计实现数据结构,首先清除这种数据结构的特点是什么,了解要用什么的方式来实现这种数据结构。

  3. 过程中出现了好多的细节错误,导致进度缓慢,使用了大量时间调试,例如:赋值运算

符重载,深浅拷贝构造的问题,函数传参时传的形参,而不能改变实体等等。

  1. 该实验使用的环境是Clion配置的MinGW,对实验中遇到的各种问不断地修正调试,加强了对这款编译器的熟练度。
  2. 实验中存在的问题是,把数据写入到文件中字符编码异常,尝试修改,未成功,应该是clion的配置存在问题。
  3. 掌握了通过单链表和静态链表来实现线性表,对单链表和静态链表更加熟悉,在实验三中又锻炼了线性表的使用。
  4. 理解了好多编程过程的小细节,const,常引用,引用,指针,delete等许多细节。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构实验题目 实验一 学生成绩管理(链表)  实验目的:熟练掌握单链表操作的基本算法实现。  实现功能:以带表头结点的单链表为存储结构,实现如下学生成绩管理的设计要求。  实验机时:6  设计要求: (1)定义学生成绩链表结点结构类型,以xscjList和*XscjLink命名,数据域:学号NO、姓名Name、手机号MTel、邮箱地址Email、籍贯 BornAddr、A分成绩AScore、B分成绩BScore,指针域:*next; (2)实现创建学生成绩链表函数void Build(XscjLink &T),输入学号、姓名、手机号、邮箱地址、籍贯、A分成绩、B分成绩,建议用文件操作来输入数据; (3)实现函数void Update(XscjLink T, char *Name, float *ScoreA),将姓名为Name的学生的A分成绩改为ScoreA; (4)实现输出学生成绩信息void OutPut(XscjLink T),输出所有学生的学号、姓名、手机号、邮箱地址、籍贯、A分成绩、B分成绩; (5) 实现函数void Insert(XscjLink T, char *Name, char *No),插入学号为NO,姓名为Name学生信息,将链表中学号≤NO的结点放到该结点的前面,将学号>NO的结点放到该结点后面; (6)实现函数void Sort(XscjLink T),将该学生按照B分成绩进行非递减排序; (7)实现函数void Merge(XscjLink &T1;, XscjLink &T2;),将两个按B分成绩非递减排序的学生成绩单合并为一个按B分成绩非递增排序的通讯录,B分成绩相同且学号相同的成绩记录在结果中只保留一个;要求算法的时间复杂度不超过两个链表的长度之和O(m+n); (8)实现函数int Count(XscjLink T);统计籍贯是“广州”的学生人数; (9)实现函数void MoveK(XscjLink T, int k),将学生成绩链表中倒数第k个结点之后的所有结点移到头结点后面(保持结点间的先后顺序),注意:严禁采用先计算链表长度n再减k(即n-k)的方法;要求算法的时间复杂度不超过个链表的长度O(n); (10)实现函数void ReverseN(XscjLink T),将学生成绩链表的正中间位置结点之后的全部结点倒置,注意:严禁采用先计算链表长度n再除以2(即n/2)的方法;要求算法的时间复杂度不超过个链表的长度O(n); (11)主控函数main()调用以上函数,分别输出(2)、(3)、(5)、(6)、(7)、(8)、(9)(10)处理后的链表内容、输出籍贯是“广州”的学生人数。 可能用到的函数: 从文件中读取学生成绩数据:fscanf(文件指针,"%s %s %s %s %s %f %f", p->NO, p->Name, p->Mtel, p->Email, p-> BornAddr, p->AScore, p->BScore); 输出学生成绩数据:printf("%s %s %s %s %s %f %f", p->NO, p->Name, p->Mtel, p->Email, , p-> BornAddr, p->AScore, p->BScore); 字符串赋值函数:char * strcpy(char *, const char *); 字符串比较函数:int strcmp(const char *, const char *) #include #include #include //定义学生成绩链表结点结构 typedef struct XscjNode { char NO[10]; //学号 char Name[16]; //姓名 char MTel[11]; //手机号 char EMail[16]; //邮箱地址 char BornAddr[20]; //籍贯(值域:"北京"、"上海"、"大连"等等,只写城市名称) float AScore; // A分成绩 float BScore; //B分成绩 struct XscjNode *next; //指针域 }XscjList, *XscjLink; 实验二 Huffman编码(二叉树)  实验目的:熟练掌握二叉树应用(Huffman编码)的基本算法实现。  实现功能:对输入的一串电文字符实现Huffman编码,再对Huffman编码生成的代码串进行译码,输出电文字符串。实现功能如下: • Huffman树的建立 • Huffman编码的生成 • 编码文件的译码  实验机时:10  设计思路: 数据结构: #define n 100 //叶子结点数 #define m 2*n-1 // Huffman树中结点总数 typedef struct { char data; 字符 int weight; //权值 int lchild , rchild , parent; //左右孩子及双亲指针 }HTNode; //树中结点类型 typedef HTNode HuffmanTree[m+1]; //0号单元不用 主要实现函数:  统计字符串中字符的种类以及各类字符的个数的函数  构造Huffman树的函数  Huffman编码的函数  建立正文的编码文件的函数  代码文件的译码函数  主函数 实验三 各种排序方法的比较  实验目的:熟练掌握内部排序算法的实现。  实现功能:编制一个演示内部排序算法比较的程序。要求通过编写程序实现起泡排序、直接插入排序、简单选择排序、快速排序、希尔排序、堆排序等常用的内部排序算法,并通过样本数据比较各个算法的时空特性  实验机时:4

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值