数据结构课程设计——计算机设计大赛——预习报告

文章描述了一款用于中国大学生计算机设计大赛江苏省组委会的赛事管理系统的设计,该系统采用二叉排序树实现参赛队伍信息的增删查改,支持按学校或赛事类别查询,具备决赛叫号功能,并提供了校园导航服务。系统还考虑了数据的存储、查询效率和健壮性测试。
摘要由CSDN通过智能技术生成

目录

一、问题定义

二、问题分析

【问题描述】

【设计要求】

【实现步骤】

【测试数据】

三、概要设计

        部分代码


一、问题定义

        本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务。

二、问题分析

【问题描述】

         该系统能够为省级赛事管理解决以下问题:

(1)能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。

(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)

(4)为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)

(5)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。

【设计要求】

1)赛事数据要求存入文件(txt或excel)并能读入查询;

2)赛地目的地查询,需提供目的地(建筑物)名称、代号、简介、两地之间路径长度等信息;

3)输入数据形式和范围:赛事相关数据可从键盘输入,或自文件导入。

4)界面要求:交互设计要合理,每个功能可以设计菜单,用户根据提示,完成相关功能的要求。

【实现步骤】

  1)分析任务,进行模块划分。

2)定义数据结构,建议按照抽象数据类型的定义、表示和实现来描述,用类C语言(伪代码)来描述数据的存储表示和相应操作的具体实现过程。

3)设计合适的算法来实现其功能,并绘制函数调用关系图。

【测试数据】

  要求使用全部合法数据,整体非法数据,局部非法数据。进行程序测试,以保证程序的健壮性。

三、概要设计

        部分代码


#include<iostream>
#include <limits.h>
#include <fstream>
#include <string>
#include <queue>
using namespace std;
struct Team {   //参赛队结构体
    string teamid; //参赛队编号
    string workname;//作品名称
    string School;//参赛学校
    string eventcategory;//赛事类别
    string player;//参赛者
    string teacher;//指导老师
};
struct Node {   //节点结构体
    Team data;
    Node* left;  //左节点
    Node* right; //右节点
};
class BST {
private:
    Node* c_Node(Team data) {
        Node* n_Node = new Node();
        n_Node->data = data;
        n_Node->left = NULL;
        n_Node->right = NULL;
        return n_Node;
    }
    Node* insert_Node(Node* node, Team data) {
        if (node == NULL) { // 若结点为空,将新结点作为根结点
            node_number++; //结点数+1
            return c_Node(data);
        }
        if (data.teamid < node->data.teamid) { // 如果新的节点编号小于当前结点,插到左子树
            node->left = insert_Node(node->left, data);
        }
        else if (data.teamid > node->data.teamid) { //  如果新的结点编号小于当前结点,插到左子树
            node->right = insert_Node(node->right, data);
        }
        return node;
    }
    /*基于二叉排序树的查找*/
    Node* s_Node(Node* node, string tid, int& k) {
        if (node == NULL) { // 若结点为空或没有找到,返回NULL
            return NULL;
        }
        k++; // 查找次数加一
        if (tid == node->data.teamid) { // 如果找到匹配的结点,返回该结点指针
            return node;
        }
        if (tid < node->data.teamid) { // 若查找编号小于该结点编号,在左子树中查找
            return s_Node(node->left, tid, k);
        }
        else { // 若查找编号大于该结点编号,在右子树中查找
            return s_Node(node->right, tid, k);
        }
    }
    /*中序遍历二叉排序树,输出所有的队伍信息*/
    void in_order(Node* node) {
        if (node == NULL) { // 如果结点是空的,则返回
            return;
        }
        in_order(node->left); // 遍历左子树
        printTeam(node->data); // 输出当前结点的队伍信息
        cout << endl;
        in_order(node->right); // 遍历右子树
    }

public:
    Node* root_node;      // 根结点指针
    int node_number;      //结点数
    int Search_time;     // 查找次数
    BST() {              // 构造函數
        root_node = NULL;
        node_number = 0;
        Search_time = 0;
    }

    ~BST() { // 析构函数,释放所有动态分配的空间
        delete_node(root_node); // 刪除二叉树中的所有结点
    }
    /*最小值结点*/
    Node* min_Node(Node* node) {
        if (node == NULL) return NULL; // 如果结点是空的,返回空
        while (node->left != NULL) { // 若有左子树,继续寻找
            node = node->left;
        }
        return node; // 返回最左边的结点
    }
    void delete_node(Node* node) {
        if (node == NULL) {
            return;
        }
        delete_node(node->left); // 刪除左子树
        delete_node(node->right); // 刪除右子树
        delete node; // 刪除当前结点
    }
    /*删除参赛队伍信息*/
    Node* deleteteam(Node* root, string id) {
        if (root == NULL) return root;
        if (id < root->data.teamid) { // 如果要刪除的编号小于根结点的编号,在右子树返回删除
            root->left = deleteteam(root->left, id);
        }
        else if (id > root->data.teamid) { // 如果要刪除的编号大于根结点的编号,在左子树返回删除
            root->right = deleteteam(root->right, id);
        }
        else { //找到该结点
            if (root->left == NULL && root->right == NULL) { // 该结点没有子结点,直接删除返回空
                delete root;
                return NULL;
            }
            else if (root->left == NULL) { // 该结点只有右子结点,替换成右子结点
                Node* temp = root->right;
                delete root;
                return temp;
            }
            else if (root->right == NULL) { // 该结点只有左子结点,替换成左子结点
                Node* temp = root->left;
                delete root;
                return temp;
            }
            else { // 若有两个结点,替换为左子树中最大值或右子树中最小值
                Node* temp = min_Node(root->right); // 找到右子树的最小值
                root->data = temp->data; // 最小值替换
                root->right = deleteteam(root->right, temp->data.teamid); // 删除
            }
        }
        return root; // 返回新的根结点
    }
    void insert(Team data) { //插入队伍信息
        root_node = insert_Node(root_node, data);
    }
    Node* search(string id) { //查找该编号
        int k = 0; // 记录查找次数
        Node* node = s_Node(root_node, id, k);
        Search_time += k; // 查找次数累加
        return node; // 返回查找结点
    }

    /*平均查找长度ASL*/
    double get_ASL() {
        if (node_number == 0) { // 若树为空,返回0
            return 0;
        }
        return (double)Search_time / node_number;
    }

    /*中序遍历二叉树*/
    void in_order() {
        in_order(root_node); //
    }
    /*添加队伍信息*/
    void add_Team() {
        Team s;
        cout << "请输入参赛队编号: ";
        cin >> s.teamid;
        cout << "请输入参赛队作品名称: ";
        cin >> s.workname;
        cout << "请输入参赛队学校: ";
        cin >> s.School;
        cout << "请输入参赛类别: ";
        cin >> s.eventcategory;
        cout << "请输入参赛者: ";
        cin >> s.player;
        cout << "请输入指导老师: ";
        cin >> s.teacher;
        insert(s); //将输入的信息插入到新结点中
    }
    /*修改队伍信息*/
    void modify_Team(string id) {
        deleteteam(root_node, id); // 删除结点信息
        Team s;
        cout << "请输入参赛队编号: ";
        cin >> s.teamid;
        cout << "请输入参赛队作品名称: ";
        cin >> s.workname;
        cout << "请输入参赛队学校: ";
        cin >> s.School;
        cout << "请输入参赛类别: ";
        cin >> s.eventcategory;
        cout << "请输入参赛者: ";
        cin >> s.player;
        cout << "请输入指导老师: ";
        cin >> s.teacher;
        insert(s); // 插入到二叉树中
    }
    /*/找出学校的所有参赛队伍的信息*/
    void printSchool(Node* root, string School) {

        if (root == NULL) return; // 结点为空返回
        printSchool(root->left, School); // 遍历左子树
        if (root->data.School == School) { // 当前结点和输入学校相同,输出该结点的信息
            printTeam(root->data);
            cout << "********************************" << endl;
        }
        printSchool(root->right, School); // 遍历右子树
    }
    void printTeam(Team s) {
        cout << "参赛队编号: " << s.teamid << endl;
        cout << "参赛作品名称: " << s.workname << endl;
        cout << "参赛队学校: " << s.School << endl;
        cout << "参赛类型: " << s.eventcategory << endl;
        cout << "参赛者: " << s.player << endl;
        cout << "指导老师: " << s.teacher << endl;
    }
    /*将二叉树中的队伍分配到三个教室中,使用队列存储每个教室的队伍*/
    void assignroom(Node* root, queue<Node*>& a1, queue<Node*>& a2, queue<Node*>& a3, queue<Node*>& a4, queue<Node*>& a5, queue<Node*>& a6, queue<Node*>& a7, queue<Node*>& a8, queue<Node*>& a9) {
        if (root == NULL) return; //如果节点为空,直接返回
        assignroom(root->left, a1, a2, a3, a4, a5, a6, a7, a8, a9); //分配左子树中的队伍
        if (root->data.eventcategory == "大数据实践") {
            a1.push(root);
        }
        else if (root->data.eventcategory == "信息图形设计") {
            a2.push(root);
        }
        else if (root->data.eventcategory == "数据可视化") {
            a3.push(root);
        }
        else if (root->data.eventcategory == "算法设计与应用") {
            a4.push(root);
        }
        else if (root->data.eventcategory == "移动应用开发") {
            a5.push(root);
        }
        else if (root->data.eventcategory == "医药卫生") {
            a6.push(root);
        }
        else if (root->data.eventcategory == "数字生活") {
            a7.push(root);
        }
        else if (root->data.eventcategory == "城市管理") {
            a8.push(root);
        }
        else if (root->data.eventcategory == "行业应用") {
            a9.push(root);
        }
        assignroom(root->right, a1, a2, a3, a3, a5, a6, a7, a8, a9); //分配右子树中的学生
    }

    /*模拟叫号系统*/
    void Call(queue<Node*>& a1, queue<Node*>& a2, queue<Node*>& a3, queue<Node*>& a4, queue<Node*>& a5, queue<Node*>& a6, queue<Node*>& a7, queue<Node*>& a8, queue<Node*>& a9) {

        cout << "**************************************" << endl; //打印分隔符
        while (!a1.empty()) { //如果教室不为空,叫号并出队
            Node* s = a1.front();

            cout << "大数据实践叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入大数据实践教室比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a1.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a2.empty()) {
            Node* s = a2.front();

            cout << "信息图形设计叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入信息图形设计比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a2.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a3.empty()) {
            Node* s = a3.front();

            cout << "数据可视化叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入数据可视化比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a3.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a4.empty()) {
            Node* s = a4.front();
            cout << "算法设计与应用叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入算法设计与应用比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a4.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a5.empty()) {
            Node* s = a5.front();
            cout << "移动应用开发叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入移动应用开发比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a5.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a6.empty()) {
            Node* s = a6.front();

            cout << "医药卫生叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入医药卫生比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a6.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a7.empty()) {
            Node* s = a7.front();

            cout << "数字生活叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入数字生活比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a7.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a8.empty()) {
            Node* s = a8.front();

            cout << "城市管理叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入城市管理比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a8.pop();
        }
        cout << "**************************************" << endl; //打印分隔符
        while (!a9.empty()) {
            Node* s = a9.front();

            cout << "行业应用叫号:" << s->data.teamid << " " << s->data.workname << endl;
            cout << s->data.workname << "进入行业应用比赛" << endl;
            cout << s->data.workname << "比赛结束" << endl;
            a9.pop();
        }
    }
};
/*打印参赛信息*/
void printTeam(Team s) {
    cout << "参赛队编号: " << s.teamid << endl;
    cout << "参赛作品名称: " << s.workname << endl;
    cout << "参赛队学校: " << s.School << endl;
    cout << "参赛类别: " << s.eventcategory << endl;
    cout << "参赛者: " << s.player << endl;
    cout << "指导老师: " << s.teacher << endl;
}

/*读取信息,#为分隔*/
Team read(istream& in) {
    Team s;
    getline(in, s.teamid, '#');
    getline(in, s.workname, '#');
    getline(in, s.School, '#');
    getline(in, s.eventcategory, '#');
    getline(in, s.player, '#');
    getline(in, s.teacher);
    return s;
}
/*判断文件的结束*/
bool File(ifstream& file) {
    char c = file.peek(); // 查看下一个字符
    if (c == EOF) { // 若下一个字符为文件结束符,返回true
        return true;
    }
    return false;
}
/*储存目的地信息*/
struct Destination {
    string name; // 目的地名称
    string code; // 目的地代号
    string intro; // 目的地简介
};
const int INF = INT_MAX;  //定义一个常量,表示无穷大
const int V = 10;  //定义一个常量,表示图形中节点的个数

/*找到未被访问过的距离最小的节点*/
int min_Distance(int dist[], bool visited[]) {   
    int min = INF, min_index;
    for (int v = 0; v < V; v++) {
        if (visited[v] == false && dist[v] <= min) {
            min = dist[v], min_index = v;
        }
    }
    return min_index;
}
 /*打印最短路径和长度*/
void print_Path(int parent[], int j, Destination destinations[]) { 
    if (parent[j] == -1) {
        return;
    }
    print_Path(parent, parent[j], destinations);
    cout << " -> " << destinations[j].code;
}

void printSolution(int dist[], int n, int parent[], int src, int dest, Destination destinations[]) {
    cout << "Vertex\t\tDistance\tPath";
    cout << "\n" << destinations[src].code << " -> " << destinations[dest].code << "\t\t" << dist[dest] << "\t\t" << destinations[src].code;
    print_Path(parent, dest, destinations);

}
/*实现Dijkstra算法*/
void dijkstra(int graph[V][V], int src, int dest, Destination destinations[]) {
    int dist[V]; // 储存源点到各个节点的距离
    bool visited[V]; // 储存各个节点是否被访问过
    int parent[V]; // 储存最短路径中各个节点的父节点

    for (int i = 0; i < V; i++) {// 初始化各个数组
        dist[i] = INF;
        visited[i] = false;
        parent[i] = -1;
    }
    dist[src] = 0;// 源点到自己的距离为0
    for (int count = 0; count < V - 1; count++) {// 遍历所有节点

        int u = min_Distance(dist, visited); // 找到未被访问过的距离最小的节点 

        visited[u] = true;// 标记该节点为已访问过

        for (int v = 0; v < V; v++) { // 更新该节点相邻节点的距离和父节点
            if (!visited[v] && graph[u][v] && dist[u] != INF && dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
                parent[v] = u;
            }
        }
    }
    printSolution(dist, V, parent, src, dest, destinations); // 打印最短路径和长度
}
int guide() {
    int graph[V][V] = { // 一个二维数组,表示图形中各个节点之间的距离(权值)
        {0, 144, 0, 0, 0, 0, 0, 148, 0},
        {144, 0, 148, 0, 0, 0, 0, 151, 0},
        {0, 148, 0, 147, 0, 144, 0, 0, 142},
        {0, 0, 147, 0, 149, 154, 0, 0, 0},
        {0, 0, 0, 149, 0, 150, 0, 0, 0},
        {0, 0, 144, 154, 150, 0, 142, 0, 0},
        {0, 0, 0, 0, 0, 142, 0, 141, 146},
        {148, 151, 0, 0, 0, 0, 141, 0, 147},
        {0, 0, 142, 0, 0, 0, 146,147, 0}
    };

    /*储存各个目的地的信息*/
    Destination d[V] = { {"1号组团", "A", "学生宿舍"},
                         {"3号组团", "B", "学生宿舍"},
                            {"西苑食堂", "C", "食堂"},
                            {"笃学楼", "D", "教学楼"},
                        {"文理大楼", "E", "学校主楼"},
              {"计算机学院", "F", "计算机学院办公楼"},
                            {"东苑食堂", "G", "食堂"},
                    {"体育馆", "H", "大学生活动中心"},
                         {"8号组团", "I", "学生宿舍"},
                    {"图书馆", "J", "图书馆和自习室"}
    };

    for (int i = 0; i < V; i++) {
        cout << d[i].name << "(" << d[i].code << "):" << d[i].intro << endl;
    }
    char a, b;// 创建一个字符串变量,储存两个目的地代号

    cout << "请输入目的地代号:"; // 提示两个目的地代号

    cin >> a >> b;

    int src = a - 'A';// 将输入的两个目的地代号转换为对应的节点编号
    int dest = b - 'A';

    if (src < 0 || src >= V || dest < 0 || dest >= V) {// 检查输入的两个目的地是否有效
        cout << "输入错误,请重新输入!" << endl;
        return -1;
    }
    if (src == dest) {// 检查输入的两个目的地是否相同
        cout << "输入错误,请重新输入!" << endl;
        return -1;
    }
    cout << "\n地点信息:" << endl;
    cout << d[src].name << "(" << d[src].code << "):" << d[src].intro << endl;
    cout << d[dest].name << "(" << d[dest].code << "):" << d[dest].intro << endl;
    cout << "\n最短路径和长度是:" << endl;
    dijkstra(graph, src, dest, d);//输出最短路径和长度
    return 0;
}
void c_code() {   //主程序代码
    BST tree;
    ifstream file;//导入参赛团队信息
    file.open("team.txt");
    while (!File(file)) { // 循环到文件结束
        Team s = read(file); // 读取, 每一行作为一个队伍
        tree.insert(s); // 将队伍信息插入二叉排序树
    }
    file.close();
    int a;
    string searchid, reviseid, deleteid, School1;

    cout << "************1.添加参赛队伍信息************" << endl;
    cout << "************2.修改参赛队伍信息************" << endl;
    cout << "************3.删除参赛队伍信息************" << endl;
    cout << "************4.查找参赛队伍信息************" << endl;
    cout << "************5.查找学校参赛信息************" << endl;
    cout << "************6.决赛叫号系统****************" << endl;
    cout << "************7.校园导航系统****************" << endl;
    cout << endl;
    cout << "请选择你的操作:";
    cin >> a;
    switch (a)
    {
    case 1:
        tree.add_Team();
        cout << "添加成功!" << endl;
        break;
    case 2:
        cout << "请输入你要修改的队伍编号:";
        cin >> reviseid;
        tree.modify_Team(reviseid);
        cout << "修改成功!" << endl;
        break;
    case 3:
        cout << "请输入你要删除的队伍编号:";
        cin >> deleteid;
        tree.deleteteam(tree.root_node, deleteid);
        cout << "删除成功!" << endl;
        break;
    case 4:
        while (true) { // 循环执行操作

            cout << "请输入要查找的参赛队编号,或者输入0退出程序: ";
            cin >> searchid;
            if (searchid == "0") break; // 输入0跳出循环
            Node* node = tree.search(searchid); // 在二叉树中搜索该编号对应的节点
            if (node == NULL) { // 没有找到
                cout << "查找失败" << endl;
            }
            else { // 输出队伍信息以及平均查找长度ASL
                cout << "查找成功" << endl;
                printTeam(node->data);
                cout << "平均查找长度ASL: " << tree.get_ASL() << endl;
            }
            cout << endl;
        }
        cout << "退出查找" << endl;
        break;
    case 5:
        cout << "请输入你要查找的学校名字:";
        cin >> School1;
        tree.printSchool(tree.root_node, School1);
        break;
    case 6:
    {
        queue<Node*>a1; queue<Node*>a2; queue<Node*>a3;
        queue<Node*>a4; queue<Node*>a5; queue<Node*>a6;
        queue<Node*>a7; queue<Node*>a8; queue<Node*>a9;
        tree.assignroom(tree.root_node, a1, a2, a3, a4, a5, a6, a7, a8, a9);
        cout << "**********开始模拟叫号系统**********" << endl;
        tree.Call(a1, a2, a3, a4, a5, a6, a7, a8, a9);
        break;
    }
    case 7:
        guide();
        break;
    default:
        break;
    }

}

int main() {
    c_code();
    return 0;
}



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值