数据结构课程设计——中国大学生计算机设计大赛赛事管理系统

一、问题定义

1、管理参赛队的基本信息

2、实现基于二叉排序树的查找

3、实现按参赛学校查询参赛团队

4、决赛叫号系统

5、校园导游程序

二、问题分析

管理参赛队的基本信息

队伍数据的存储:需要确定如何存储参赛队的基本信息,例如队伍ID、项目名称、学校名称、参赛类别、参赛成员、指导教师等。可以使用数据结构来存储这些信息,例如二叉搜索树(BST)或哈希表等。

队伍数据的添加和删除:需要实现功能来添加新的参赛队信息和删除已有的参赛队信息。这涉及到插入和删除节点的操作,以及对存储数据结构的更新。

队伍数据的更新:需要提供功能来更新队伍的信息。这可以通过遍历数据结构或利用索引来实现。

使用单链表来存储参赛队的基本信息具有以下优势

  1. 动态性:单链表的大小可以根据需要进行动态调整。在参赛队伍的管理中,可能需要频繁地添加、删除队伍信息,而单链表可以通过修改节点的链接来实现高效的插入和删除操作,无需重新分配内存空间。

  2. 灵活性:由于单链表的节点只包含指向下一个节点的链接,可以轻松地在链表中插入、删除或移动节点,而无需对整个链表进行重构。这样可以方便地对参赛队伍的信息进行修改和调整。

  3. 简单的插入和删除:对于单链表,插入和删除节点的操作只需要修改相邻节点的链接,不需要移动其他节点,因此插入和删除的时间复杂度为O(1)。这使得在管理参赛队伍时可以高效地进行插入和删除操作。

  4. 遍历效率高:可以从单链表的头节点开始,通过顺序访问每个节点,高效地遍历所有参赛队伍的信息。这对于列出所有队伍或进行查询操作非常方便。

  5. 节省内存空间:相比于数组等静态数据结构,单链表在存储参赛队伍信息时可以更加灵活地利用内存空间。每个节点只包含所需的数据和一个指向下一个节点的链接,而不需要预先分配固定大小的内存块。

实现基于二叉排序树的查找

实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。请输出ASL(成功)的计算表达式和结果值。

实现按参赛学校查询参赛团队 

对于按参赛学校查询参赛团队并且要求有序输出的情况,可以选择选择排序

选择排序的优势在于其简单性和易于实现。以下是选择排序的一些优势:

  1. 简单易懂:选择排序是一种直观且易于理解的排序算法。它的基本思想是通过每次选择未排序部分的最小(或最大)元素并放置在已排序部分的末尾,以逐步构建有序序列。

  2. 不占用额外空间:选择排序是一种原地排序算法,即不需要额外的辅助数组或数据结构来进行排序。它仅需要在原始数组中进行元素的交换操作,节省了空间复杂度。

  3. 最好情况下的性能优势:选择排序在最好情况下的比较次数是确定的。无论输入数据的顺序如何,都需要进行 n-1 次比较操作,其中 n 是待排序元素的个数。这使得选择排序在某些特定场景下(如已经基本有序的序列)可能比其他排序算法更加高效。

  4. 对于小规模数据或部分有序数据的适应性:由于选择排序的特点,它在处理小规模数据或者部分有序的数据时可能表现良好。因为选择排序的比较次数是固定的,不受数据规模的影响,并且对已经有序的部分不会进行多余的比较操作。

 决赛叫号系统

首先是遍历所有的队伍节点,然后按赛事类别把分开,之后使用选择排序把把队伍按编号排序,最后建立九个进程模拟叫号过程

校园导游程序

这显然是一个图论问题,而且校园内道路一般是双向通行的,所以这是一个无向图。对 于图的存储结构而言,图中各个景点的存储结构有邻接表和邻接矩阵两种存储结构,考虑到 顶点个数少于 50 个,所以邻接表和邻接矩阵的复杂度相同。本题中选择使用邻接矩阵来表 示图。 任务中要求求解出图中景点的问路查询,即为给定两个源点,求解出两个顶点之间的最 短路径。根据数据结构课程所学知识,有多种经典算法可以解决最短路径问题,包括 Dijkstra 算法,Floyd-Warshell 算法,Bellman-Ford 算法和深度优先遍历。不同是算法有不同的算法复 杂度,考虑到校园中道路没有负权边,即算法均可解决最短路径问题。 其中 Dijkstra 算法求的是单源最短路径:即从一个结点出发到其它所有结点的最短路径, 算法的时间复杂度为 O(n 2 ),但题目要求任意两个结点的最短路径,所以还是要在外层增加 一个循环,以求得多源最短路径。 而 Floyd 算法求的是多源最短路径:即从任意结点出发到其它所有结点的最短路径,算 法的时间复杂度为 O(n 3 ),它可以一次性求得所有结点间的最短路径,且算法思想简单,便 于理解。所以我们这一项目采用 dijkstra

三、概要设计

1、管理参赛队的基本信息

读写工具类 FileIO,其中包含了两个静态方法:readTeamsFromFile()writeTeamsToFile()

  1. readTeamsFromFile() 方法用于从文件中读取参赛团队信息并创建团队链表。它接收一个文件名作为参数,并返回一个团队链表对象。

    • 首先,通过创建 BufferedReader 对象和使用 FileReader 从文件中读取数据。
    • 然后,使用 readLine() 方法逐行读取文件内容,直到读取到末尾(返回值为 null)。
    • 对于每一行数据,使用 \t#\t 作为分隔符将数据拆分为不同的字段。
    • 将拆分后的字段转换为相应的类型,并使用它们创建一个新的 Team 对象。
    • 将新创建的团队对象添加到团队链表中。
    • 最后,返回完整的团队链表对象。
  2. writeTeamsToFile() 方法用于将团队链表中的参赛团队信息写入文件。它接收一个团队链表对象和一个文件名作为参数。

    • 首先,通过创建 BufferedWriter 对象和使用 FileWriter 打开文件以进行写操作。
    • 使用团队链表的 getHead() 方法获取链表的头节点。
    • 循环遍历团队链表,直到链表结束。
    • 对于每个团队,使用 write() 方法将团队的各个字段以 \t#\t 作为分隔符写入文件。
    • 在每行数据的末尾添加换行符 \n
    • 最后,关闭文件写入流。

Team 类包含了私有字段 teamNumberprojectNameschooleventCategoryparticipantsguideTeacher,分别表示团队的编号、项目名称、学校、赛事类别、参与者和指导教师。

这个 Team 类可以在团队链表的实现中使用,每个 Team 对象表示一个团队的信息,通过 next 字段连接在一起形成一个链表。链表的头节点可以通过调用 getHead() 方法获取。可以使用这个类来创建、修改和访问团队的属性,并在链表中进行操作。

定义了一个 TeamLinkedList 类,表示团队链表。它包含了管理团队链表的操作方法,例如添加团队、删除团队、更新团队信息等。

以下是这段代码的思路:

  1. TeamLinkedList 类包含了一个私有字段 head,表示链表的头部。
  2. 类中的构造函数用于初始化链表,将头部设置为 null
  3. getHead() 方法用于获取链表的头部。
  4. addTeam() 方法用于从用户输入中添加一个新的团队。它会提示用户输入团队的各个属性,然后创建一个新的 Team 对象,并调用 addTeam(Team newTeam) 方法将其添加到链表末尾。
  5. addTeam(Team newTeam) 方法用于将给定的团队对象添加到链表末尾。如果链表为空,则将该团队对象作为头部;否则,遍历链表直到末尾,然后将新团队对象链接到链表的末尾。
  6. deleteTeam() 方法用于从用户输入中删除一个团队。它会提示用户输入要删除的团队编号,然后调用 deleteTeam(int teamNumber) 方法进行删除。
  7. deleteTeam(int teamNumber) 方法用于根据给定的团队编号从链表中删除团队。它会遍历链表,找到匹配的团队编号并删除对应的团队节点。
  8. updateTeam() 方法用于从用户输入中更新一个团队的信息。它会提示用户输入要更新的团队编号,然后根据用户输入的信息创建一个新的 Team 对象,并调用 updateTeam(int teamNumber, Team updatedTeam) 方法进行更新。
  9. updateTeam(int teamNumber, Team updatedTeam) 方法用于根据给定的团队编号找到相应的团队节点,并更新其属性值为新的团队对象的属性值。
  10. isTeamNumberExists(int teamNumber) 方法用于检查给定的团队编号是否已存在于链表中。
  11. findTeamById() 方法用于从用户输入中查找一个团队的信息。它会提示用户输入要查找的团队编号,并从文件中读取团队信息,然后使用二叉排序树进行查找操作。
  12. searchBySchool(String school) 方法用于根据给定的学校名称在链表中搜索匹配的团队。它会遍历链表,找到学校名称与给定名称相匹配的团队,并将其存储在一个列表中。

2、实现基于二叉排序树的查找

定义了一个 BinarySearchTree 类,表示二叉排序树。它用于存储参赛队伍的信息,并支持插入和查找操作。

以下是这段代码的思路:

  1. BinarySearchTree 类中定义了一个内部静态类 Node,表示二叉排序树的节点。每个节点包含一个参赛队编号和对应的参赛团队信息,以及左子节点和右子节点的引用。
  2. 类中定义了 root 字段,表示二叉排序树的根节点。还有 nodeCount 字段,表示二叉排序树中节点的数量,以及 searchCount 字段,表示查找操作的次数。
  3. 类中的构造函数初始化根节点为 null,节点数量和查找次数为 0。
  4. insert(int teamNumber, Team team) 方法用于向二叉排序树中插入节点。它接受参赛队编号和参赛团队信息作为参数。在递归方式下,根据节点的大小关系选择插入到左子树或右子树,并更新节点数量。
  5. insertNode(Node node, int teamNumber, Team team) 是一个辅助方法,用于在指定的节点下插入新的节点。如果节点为空,则创建一个新节点并返回;否则,根据参赛队编号的大小关系递归调用插入方法,更新左子节点或右子节点的引用。
  6. search(int teamNumber) 方法用于在二叉排序树中查找节点并输出基本信息。它接受参赛队编号作为参数。首先调用 searchNode(Node node, int teamNumber) 方法来查找节点,如果找到了匹配的节点,就输出参赛团队的信息和查找次数。
  7. searchNode(Node node, int teamNumber) 是一个辅助方法,用于在指定的节点下查找匹配的节点。在每次递归中,根据参赛队编号与节点的大小关系进行比较,选择左子节点或右子节点进行下一轮查找。同时,更新查找次数。
  8. 在成功查找到节点后,输出参赛团队的基本信息,并计算平均查找长度 ASL(Average Search Length)作为评估指标。

3、实现按参赛学校查询参赛团队

定义了一个 TeamSearchBySchool 类,用于按照参赛学校查询参赛团队并输出结果。

以下是这段代码的思路:

  1. TeamSearchBySchool 类包含一个私有字段 teamList,表示要进行搜索的团队链表。
  2. 类中的构造函数接受一个 TeamLinkedList 对象作为参数,并将其赋值给 teamList 字段。
  3. searchBySchool() 方法用于按照参赛学校查询参赛团队,并输出结果。它会提示用户输入参赛学校的名称,然后调用 teamListsearchBySchool(String school) 方法获取匹配的团队数组。
  4. 如果找到了匹配的团队,就会使用选择排序算法对团队数组按参赛队编号进行排序,并逐个输出团队的信息。
  5. 如果没有找到匹配的团队,则会输出相应的提示信息。
  6. selectionSort(Team[] teams) 方法使用选择排序算法对团队数组按参赛队编号进行排序。它会遍历团队数组,找到最小的参赛队编号,并将其与当前位置的团队进行交换,以达到排序的目的。
  7. swap(Team[] teams, int i, int j) 方法用于交换团队数组中的两个元素。它接受一个团队数组以及两个元素的索引作为参数,并通过临时变量实现两个元素的交换。

4、决赛叫号系统

  1. FinalCallSystem 类中定义了私有的决赛室列表 finalRoom1finalRoom9,每个列表对应不同的决赛室。

  2. assignTeams() 方法中,通过遍历参赛队伍列表,将队伍根据赛事类别分配到对应的决赛室列表中。

  3. announceTeams() 方法中,按照决赛室的顺序,依次输出每个决赛室中的队伍信息。

  4. simulateFinals() 方法用于模拟决赛过程。它先调用 assignTeams() 方法进行队伍分配,然后创建一个线程列表,每个决赛室对应一个线程。每个线程调用 simulateFinalRoom() 方法进行决赛模拟。

  5. simulateFinalRoom() 方法接收一个决赛室列表和决赛室名称作为参数,在该决赛室中模拟比赛过程。遍历决赛室中的队伍,输出当前比赛队伍所在的决赛室、队伍编号、参赛作品名称,并模拟比赛过程(这里用 Thread.sleep() 模拟比赛时间)。

5、校园导游程序

  1. 首先定义了一个 Vertex 类,表示图中的顶点。每个顶点包含一个顶点编号、顶点名称和顶点简介。
  2. 接下来定义了一个 Graph 类,表示图结构。其中包含顶点数量、顶点数组和邻接矩阵。邻接矩阵用于存储顶点之间的边和权重信息。
  3. Graph 类的构造函数接受顶点数量作为参数,初始化顶点数组和邻接矩阵。初始时,将邻接矩阵中的所有元素设置为最大值表示无穷大的权重。
  4. Graph 类提供了添加顶点和添加边的方法。addVertex(Vertex vertex) 方法用于向图中添加顶点,将顶点对象存储在对应位置的顶点数组中。addEdge(int source, int destination, int weight) 方法用于添加边,将边的权重存储在邻接矩阵中对应的位置上。
  5. Graph 类还提供了获取顶点信息的方法 getVertex(int vertexId),根据顶点编号返回对应的顶点对象。
  6. 接下来定义了一个 ShortestPath 类,用于执行最短路径算法。它包含一个 Graph 对象作为成员变量,用于进行最短路径计算。
  7. ShortestPath 类的构造函数接受一个 Graph 对象作为参数,并将其保存到成员变量中。
  8. ShortestPath 类实现了 Dijkstra 算法来计算最短路径。dijkstra(int source, int destination) 方法接受起始顶点和目标顶点作为参数。在该方法中,使用数组 distance 记录起始顶点到各顶点的最短距离,使用数组 previous 记录最短路径上每个顶点的前驱顶点,使用数组 visited 记录顶点是否已被访问。通过迭代过程,逐步更新最短距离和前驱顶点,直到找到最短路径。
  9. printShortestPath(int[] previous, int destination) 方法是一个递归方法,用于打印最短路径。通过递归调用,从目标顶点的前驱顶点开始回溯,直到达到起始顶点,打印路径上的顶点名称。
  10. dijkstra(int source, int destination) 方法中,最后将最短路径和最短路径距离组合成一个字符串 inf,并返回该字符串作为最终的结果。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值