数据结构 程序设计

  • 课程设计内容 
  • 问题概述
  • 设计要求
  • 概要设计

1、课程设计内容


       中国大学生计算机设计大赛是我国高校面向本科生的计算机应用设计大赛,大赛旨在激发学生学习计算机知识和技能的兴趣与潜能,提高学生运用信息技术解决实际问题的综合能力。通过大赛这种计算机教学实践形式,可展示师生的教与学成果,最终以赛促学,以赛促教,以赛促创。该赛事在历届学生中影响力较大,参与者众多,请结合2021届省赛参赛的数据,借助数据结构课程所学的相关知识,通过对数据的处理和分析,熟悉数据结构设计及数据处理在信息管理系统中应用的重要性。

2、问题概述


本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:

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

(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。

(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)

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

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

3、设计要求


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

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

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

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

求。

4、概要设计


一  查找系统

struct Team {
    string id;     // 参赛队编号
    string name;   // 参赛作品名称
    string school; // 参赛学校
    string type;   // 赛事类别
    string member; // 参赛者信息
    string tutor;  // 指导老师信息
};

struct TreeNode {
    Team data;
    TreeNode* left;     // 左子树指针
    TreeNode* right;    // 右子树指针
};

TreeNode* root;   // 定义全局变量作为根节点指针
int count1 = 0;   // 定义全局变量记录添加的队伍数

void Remove(string& s)
{    //去除字符串中的空格
    int index = 0;
    if (!s.empty()) {
        while ((index = s.find('\t', 0)) != string::npos)
        { // 进行转行 ,不然无法清除
            s.erase(index, 1);
        }
    }
}

void Insert(TreeNode*& root, Team team) {
    if (root == nullptr) {
        root = new TreeNode;
        root->data = team;
        root->left = nullptr;
        root->right = nullptr;
    }
    else if (team.id < root->data.id) {
        Insert(root->left, team);
    }
    else {
        Insert(root->right, team);
    }
}

void Read() {
    ifstream i;
    i.open("team.txt");
    string Temp;
    while (getline(i, Temp)) {
        Remove(Temp);
        Team team{};
        for (int j = 0; j < 6; j++) {
            int Position = Temp.find('#');
            string s = Temp.substr(0, Position);
            Temp = Temp.substr(Position + 1);
            if (j == 0)
            {
                team.id = s;
            }
            if (j == 1)
            {
                team.name = s;
            }
            if (j == 2)
            {
                team.school = s;
            }
            if (j == 3)
            {
                team.type = s;
            }
            if (j == 4)
            {
                team.member = s;
            }
            if (j == 5)
            {
                team.tutor = s;
            }
        }
        Insert(root, team);   // 在读取队伍信息后立即插入到二叉排序树中
        count1++;    // 每次添加队伍信息后,记录数量加 1
    }
    cout << "成功读取 " << count1 << " 条队伍信息!\n";
    i.close();
}

void InorderTraversal(TreeNode* root) {
    if (root != nullptr) {
        InorderTraversal(root->left);
        cout << "\n参赛队编号:" << root->data.id << "\n"
            << "参赛作品名称:" << root->data.name << "\n"
            << "参赛学校:" << root->data.school << "\n"
            << "参赛类别:" << root->data.type << "\n"
            << "参赛学生姓名:" << root->data.member << "\n"
            << "指导老师姓名:" << root->data.tutor << endl;
        cout << endl;
        InorderTraversal(root->right);
    }
}

void Search() {
    if (root == nullptr) {
        cout << "暂无队伍信息!\n";
        return;
    }
    cout << "请输入要查找的参赛队编号:\n";
    string id;
    cin >> id;
    TreeNode* node = root;
    while (node != nullptr && node->data.id != id) {
        if (id < node->data.id) {
            node = node->left;
        }
        else {
            node = node->right;
        }
    }
    if (node != nullptr) {
        cout << "\n参赛队编号:" << node->data.id << "\n"
            << "参赛作品名称:" << node->data.name << "\n"
            << "参赛学校:" << node->data.school << "\n"
            << "参赛类别:" << node->data.type << "\n"
            << "参赛学生姓名:" << node->data.member << "\n"
            << "指导老师姓名:" << node->data.tutor << endl;
    }
    else {
        cout << "未找到对应编号的队伍信息!\n";
    }
}

 该部分为查找系统,包含了基于二叉排序树的队伍信息查找以及读取文件信息并进行输出的功能,目前仅可通过队伍编号进行查找。

二 增删系统

void Insert() {
    cout << "请输入参赛队编号:\n";
    string id;
    cin >> id;
    TreeNode* node = root;
    while (node != nullptr && node->data.id != id) {
        if (id < node->data.id) {
            node = node->left;
        }
        else {
            node = node->right;
        }
    }
    if (node != nullptr) {
        cout << "该队伍编号已存在,添加失败!\n";
        return;
    }
    Team team{};
    team.id = id;
    cout << "请输入参赛作品名称:\n";
    cin >> team.name;
    cout << "请输入参赛学校:\n";
    cin >> team.school;
    cout << "请输入参赛类别:\n";
    cin >> team.type;
    cout << "请输入参赛学生姓名:\n";
    cin >> team.member;
    cout << "请输入指导老师姓名:\n";
    cin >> team.tutor;

    Insert(root, team);
    count1++;   // 每次添加队伍信息后,记录数量加 1
    cout << "成功添加队伍信息!\n";
}

void Delete() {
    if (root == nullptr) {
        cout << "暂无队伍信息!\n";
        return;
    }
    cout << "请输入要删除的参赛队编号:\n";
    string id;
    cin >> id;
    TreeNode* node = root;
    while (node != nullptr && node->data.id != id) {
        if (id < node->data.id) {
            node = node->left;
        }
        else {
            node = node->right;
        }
    }
    if (node == nullptr) {
        cout << "未找到对应编号的队伍信息!\n";
        return;
    }
    if (node->left == nullptr) {  // 如果只有右子树或没有子节点,则直接将右子树或空指针赋给当前节点的父节点指针
        root = node->right;
    }
    else if (node->right == nullptr) {  // 如果只有左子树,则直接将左子树赋给当前节点的父节点指针
        root = node->left;
    }
    else {  // 如果被删除节点有两个子节点
        TreeNode* parent = nullptr;
        TreeNode* minNode = node->right;   // 查找右子树中的最小节点
        while (minNode->left != nullptr) {
            parent = minNode;
            minNode = minNode->left;
        }
        if (parent != nullptr) {
            parent->left = minNode->right;   // 将右子树中的最小节点的右子树赋给其父节点的左指针
            minNode->right = node->right;    // 将被删除节点的右子树赋给最小节点的右指针
        }
        else {
            root = minNode;     // 如果被删除节点的右子树没有左子树,则直接将右子树赋给当前节点的父节点指针
            minNode->left = node->left;   // 将被删除节点的左子树赋给最小节点的左指针
        }
        delete node;   // 释放被删除节点的内存空间
        count1--;       // 每次删除队伍信息后,记录数量减 1
        cout << "成功删除队伍信息!\n";
    }
}
    void Update() {
        if (root == nullptr) {
            cout << "暂无队伍信息!\n";
            return;
        }
        cout << "请输入要修改的参赛队编号:\n";
        string id;
        cin >> id;
        TreeNode* node = root;
        while (node != nullptr && node->data.id != id) {
            if (id < node->data.id) {
                node = node->left;
            }
            else {
                node = node->right;
            }
        }
        if (node == nullptr) {
            cout << "未找到对应编号的队伍信息!\n";
            return;
        }

        cout << "\n参赛队编号:" << node->data.id << "\n"
            << "参赛作品名称:" << node->data.name << "\n"
            << "参赛学校:" << node->data.school << "\n"
            << "参赛类别:" << node->data.type << "\n"
            << "参赛学生姓名:" << node->data.member << "\n"
            << "指导老师姓名:" << node->data.tutor << endl;

        cout << "请选择要修改的信息:\n1.参赛作品名称\n2.参赛学校\n3.参赛类别\n4.参赛学生姓名\n5.指导老师姓名\n";
        int choice;
        cin >> choice;

        switch (choice)
        {
        case 1:
            cout << "请输入新的参赛作品名称:\n";
            cin >> node->data.name;
            break;
        case 2:
            cout << "请输入新的参赛学校:\n";
            cin >> node->data.school;
            break;
        case 3:
            cout << "请输入新的参赛类别:\n";
            cin >> node->data.type;
            break;
        case 4:
            cout << "请输入新的参赛学生姓名:\n";
            cin >> node->data.member;
            break;
        case 5:
            cout << "请输入新的指导老师姓名:\n";
            cin >> node->data.tutor;
            break;
        default:
            cout << "输入错误!\n";
            break;
        }

        cout << "\n参赛队编号:" << node->data.id << "\n"
            << "参赛作品名称:" << node->data.name << "\n"
            << "参赛学校:" << node->data.school << "\n"
            << "参赛类别:" << node->data.type << "\n"
            << "参赛学生姓名:" << node->data.member << "\n"
            << "指导老师姓名:" << node->data.tutor << endl;

        cout << "成功修改队伍信息!\n";
    }

该部分为增删系统。包含了添加队伍信息、删除队伍信息、修改队伍信息的功能。

三 叫号系统

void call(int treeSize) {
        if (root == nullptr) {
            cout << "暂无队伍信息!\n";
            return;
        }
        // 定义一个map,用来存储赛事类别和对应的参赛队伍
        map<string, vector<TreeNode*>> teamMap;
        vector<TreeNode*> nodeStack;  // 定义一个栈来存储遍历过的节点
        nodeStack.push_back(root);
        while (!nodeStack.empty()) {
            TreeNode* node = nodeStack.back();
            nodeStack.pop_back();
            if (node != nullptr) {
                teamMap[node->data.type].push_back(node);  // 根据赛事类别将参赛队伍添加到对应的vector中
                nodeStack.push_back(node->right);
                nodeStack.push_back(node->left);
            }
        }

        srand((unsigned int)time(NULL));  // 初始化随机数种子
        int count = 0;
        while (count < treeSize) {
            for (int i = 1; i <= 9; i++) {   // 循环九次,表示九个决赛室
                cout << "=======================\n";
                cout << "第 " << i << " 个决赛室叫号:\n";

                // 随机选择一支队伍
                bool found = false;
                for (map<string, vector<TreeNode*>>::iterator it = teamMap.begin(); it != teamMap.end(); ++it) {
                    vector<TreeNode*> teamVec = it->second;
                    if (!teamVec.empty()) {   // 如果当前类别的队伍还有剩余,则从中选择一个
                        int teamIndex = rand() % teamVec.size();  // 随机选择一个队伍
                        TreeNode* teamNode = teamVec[teamIndex];

                        cout << "参赛队编号:" << teamNode->data.id << "\n"
                            << "参赛作品名称:" << teamNode->data.name << "\n"
                            << "参赛学校:" << teamNode->data.school << "\n"
                            << "参赛类别:" << teamNode->data.type << "\n"
                            << "参赛学生姓名:" << teamNode->data.member << "\n"
                            << "指导老师姓名:" << teamNode->data.tutor << endl;

                        // 删除被选择的参赛队伍,避免重复叫号
                        teamVec.erase(teamVec.begin() + teamIndex);
                        teamMap[it->first] = teamVec;
                        count++;
                        found = true;
                        break;
                    }
                }
                if (!found) {   // 如果所有类别的队伍都已经叫完,则直接退出循环
                    cout << "所有队伍已经叫完!\n";
                    return;
                }
            }
        }
    }

 该部分为叫号系统。包含了随机将所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号。可以自行输入需要进行叫号的队伍数量。

四 导航系统

unordered_map<int, vector<pair<int, int>>> graph = {
    {1, {{2, 150}, {4, 250}}},
    {2, {{1, 150}, {3, 100}, {4, 200}}},
    {3, {{2, 100}, {4, 130},{6,120}}},
    {4, {{1, 250}, {2, 200}, {3, 150},{5,100},{9,300}}},
    {5, {{4, 100}, {6, 150} ,{7,100}}},
    {6, {{3, 120}, {5, 150},{8,90}}},
    {7, {{5, 100}, {9, 80},{10,100}}},
    {8, {{6, 90}, {10, 200}}},
    {9, {{4, 300}, {7, 80},{10,40}}},
    {10, {{7, 100}, {8, 200}, {9, 40}}}
    };

    void navigate(int start, int end) {
        int n = graph.size();
        unordered_map<int, int> dist; // 距离数组存储起点到每个节点的最短距离
        priority_queue<pair<int, int>> pq; // 小根堆存储未遍历的节点
        pq.push(make_pair(0, start)); // 将起点加入小根堆

        for (int i = 1; i <= n; ++i) {
            dist[i] = INT_MAX;
        }
        dist[start] = 0; // 初始化起点距离为0

        while (!pq.empty()) {
            int node = pq.top().second;
            pq.pop();

            for (auto neighbor : graph[node]) {
                int nextNode = neighbor.first;
                int weight = neighbor.second;
                int newDistance = dist[node] + weight; // 计算新距离

                if (dist.find(nextNode) == dist.end() || dist[nextNode] > newDistance) {
                    dist[nextNode] = newDistance;
                    pq.push(make_pair(-newDistance, nextNode));
                }
            }
        }

        // 输出最短路径
        if (dist.find(end) == dist.end()) {
            cout << "无法到达终点!\n";
        }
        else {
            vector<int> path; // 存储路径上的节点
            int node = end;
            while (node != start) {
                path.push_back(node);
                for (auto neighbor : graph[node]) {
                    int prevNode = neighbor.first;
                    int weight = neighbor.second;
                    if (dist[node] == dist[prevNode] + weight) {
                        node = prevNode;
                        break;
                    }
                }
            }
            path.push_back(start);
            reverse(path.begin(), path.end());
            cout << "最短路径为:" << dist[end] <<"米" << ",路径为:" << path[0];
            for (int i = 1; i < path.size(); ++i) {
                cout << " -> " << path[i];
            }
            cout << endl;
        }
    }

 该部分为导航系统。可为参赛者提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。

五 主函数

int main() {
        int choice;
        do {
            cout << "\n==========================\n";
            cout << "欢迎使用参赛队伍信息管理系统\n";
            cout << "--------------------------\n";
            cout << "1.读取参赛队伍信息\n";
            cout << "2.查找参赛队伍信息\n";
            cout << "3.添加参赛队伍信息\n";
            cout << "4.删除参赛队伍信息\n";
            cout << "5.修改参赛队伍信息\n";
            cout << "6.输出所有参赛队伍信息\n";
            cout << "7.保存参赛队伍信息到文件\n";
            cout << "8.叫号\n";
            cout << "9.进场\n";
            cout << "10.退出\n";
            cout << "==========================\n";
            cin >> choice;
            switch (choice)
            {
            case 1:
                Read();
                break;
            case 2:
                Search();
                break;
            case 3:
                Insert();
                break;
            case 4:
                Delete();
                break;
            case 5:
                Update();
                break;
            case 6:
                InorderTraversal(root);
                break;
            case 7:
                Write();
                break;
            case 8:
               int num;
                cout << "请输入参赛队伍的数量:" << endl;
                cin >> num;
                call(num);
                break;
            case 9:
                int start, end;
                cout << "以下是所有的比赛场地:" << endl;
                cout << "--------------------------\n";
                cout << "1.3号组团" << endl;
                cout << "2.西苑食堂" << endl;
                cout << "3.明德园" << endl;
                cout << "4.文体中心" << endl;
                cout << "5.文心园" << endl;
                cout << "6.文理大楼" << endl;
                cout << "7.求索园" << endl;
                cout << "8.梦溪园" << endl;
                cout << "9.东苑食堂" << endl;
                cout << "10.图书馆" << endl;
                cout << "--------------------------\n";
                cout << "请输入起点和终点:\n";
                cin >> start >> end;
                navigate(start, end);
                break;
            case 10:
                cout << "感谢使用本系统,再见!\n";
                exit(0);   // 退出程序
                break;
            default:
                cout << "输入错误!\n";
                break;
            }
        } while (choice != 8);

        return 0;
    }

 该代码为主函数。

源代码

#include <iostream>
#include <string>
#include <fstream>            
#include <map>
#include <vector>
#include <stdlib.h>
#include <stack>
#include <unordered_map>
#include <queue>
#include <climits>
#include <algorithm>
#include <iomanip>

using namespace std;

struct Team {
    string id;     // 参赛队编号
    string name;   // 参赛作品名称
    string school; // 参赛学校
    string type;   // 赛事类别
    string member; // 参赛者信息
    string tutor;  // 指导老师信息
};

struct TreeNode {
    Team data;
    TreeNode* left;     // 左子树指针
    TreeNode* right;    // 右子树指针
};

TreeNode* root;   // 定义全局变量作为根节点指针
int count1 = 0;   // 定义全局变量记录添加的队伍数

void Remove(string& s)
{    //去除字符串中的空格
    int index = 0;
    if (!s.empty()) {
        while ((index = s.find('\t', 0)) != string::npos)
        { // 进行转行 ,不然无法清除
            s.erase(index, 1);
        }
    }
}

void Insert(TreeNode*& root, Team team) {
    if (root == nullptr) {
        root = new TreeNode;
        root->data = team;
        root->left = nullptr;
        root->right = nullptr;
    }
    else if (team.id < root->data.id) {
        Insert(root->left, team);
    }
    else {
        Insert(root->right, team);
    }
}

void Read() {
    ifstream i;
    i.open("team.txt");
    string Temp;
    while (getline(i, Temp)) {
        Remove(Temp);
        Team team{};
        for (int j = 0; j < 6; j++) {
            int Position = Temp.find('#');
            string s = Temp.substr(0, Position);
            Temp = Temp.substr(Position + 1);
            if (j == 0)
            {
                team.id = s;
            }
            if (j == 1)
            {
                team.name = s;
            }
            if (j == 2)
            {
                team.school = s;
            }
            if (j == 3)
            {
                team.type = s;
            }
            if (j == 4)
            {
                team.member = s;
            }
            if (j == 5)
            {
                team.tutor = s;
            }
        }
        Insert(root, team);   // 在读取队伍信息后立即插入到二叉排序树中
        count1++;    // 每次添加队伍信息后,记录数量加 1
    }
    cout << "成功读取 " << count1 << " 条队伍信息!\n";
    i.close();
}

void InorderTraversal(TreeNode* root) {
    if (root != nullptr) {
        InorderTraversal(root->left);
        cout << "\n参赛队编号:" << root->data.id << "\n"
            << "参赛作品名称:" << root->data.name << "\n"
            << "参赛学校:" << root->data.school << "\n"
            << "参赛类别:" << root->data.type << "\n"
            << "参赛学生姓名:" << root->data.member << "\n"
            << "指导老师姓名:" << root->data.tutor << endl;
        cout << endl;
        InorderTraversal(root->right);
    }
}

float asl(TreeNode* root, int depth =0)
{
    if (root == nullptr)
    {
        return 0;
    }
    else {
        float leftASL = asl(root->left, depth + 1);
        float rightASL = asl(root->right, depth + 1);
        return(leftASL + rightASL + depth);
    }
}

void Search() {
    if (root == nullptr) {
        cout << "暂无队伍信息!\n";
        return;
    }

    int choice;
    cout << "请输入查询方式:\n"
        << "1. 参赛队编号\n"
        << "2. 参赛作品名称\n"
        << "3. 参赛学校\n";
    cin >> choice;

    bool flag = false;  // 用来判断是否找到了匹配的队伍
    string keyword;
    switch (choice) {
    case 1:
        cout << "请输入参赛队编号:";
        cin >> keyword;
        break;
    case 2:
        cout << "请输入参赛作品名称:";
        cin >> keyword;
        break;
    case 3:
        cout << "请输入参赛学校:";
        cin >> keyword;
        break;
    default:
        cout << "输入有误,请重新选择。\n";
        return;
    }

    
    vector<TreeNode*> result;  // 用来存储匹配的队伍
    vector<TreeNode*> nodeStack;  // 定义一个栈来存储遍历过的节点
    nodeStack.push_back(root);
    while (!nodeStack.empty()) {
        TreeNode* node = nodeStack.back();
        nodeStack.pop_back();
        if (node != nullptr) {
            switch (choice) {   // 根据选择的方式进行匹配
            case 1:
                if (node->data.id == keyword) {
                    result.push_back(node);
                    flag = true;
                }
                break;
            case 2:
                if (node->data.name == keyword) {
                    result.push_back(node);
                    flag = true;
                }
                break;
            case 3:
                if (node->data.school == keyword) {
                    result.push_back(node);
                    flag = true;
                }
                break;
            }
            nodeStack.push_back(node->right);
            nodeStack.push_back(node->left);
        }
    }

    if (!flag) {   // 如果没有找到匹配的队伍,则输出提示信息
        cout << "没有找到匹配的队伍!\n";
    }
    else {   // 否则输出所有匹配的队伍信息以及平均查找长度 ASL
        cout << "共找到 " << result.size() << " 支队伍:\n";
        for (int i = 0; i < result.size(); i++) {
            TreeNode* node = result[i];
            cout << "参赛队编号:" << node->data.id << "\n"
                << "参赛作品名称:" << node->data.name << "\n"
                << "参赛学校:" << node->data.school << "\n"
                << "参赛类别:" << node->data.type << "\n"
                << "参赛学生姓名:" << node->data.member << "\n"
                << "指导老师姓名:" << node->data.tutor << "\n\n";
        }
        double asl_num = asl(root) / 398.0;
        cout << "平均查找长度 ASL = " <<  asl_num << endl; // 输出平均查找长度
    }
}


void Insert() {
    cout << "请输入参赛队编号:\n";
    string id;
    cin >> id;
    TreeNode* node = root;
    while (node != nullptr && node->data.id != id) {
        if (id < node->data.id) {
            node = node->left;
        }
        else {
            node = node->right;
        }
    }
    if (node != nullptr) {
        cout << "该队伍编号已存在,添加失败!\n";
        return;
    }
    Team team{};
    team.id = id;
    cout << "请输入参赛作品名称:\n";
    cin >> team.name;
    cout << "请输入参赛学校:\n";
    cin >> team.school;
    cout << "请输入参赛类别:\n";
    cin >> team.type;
    cout << "请输入参赛学生姓名:\n";
    cin >> team.member;
    cout << "请输入指导老师姓名:\n";
    cin >> team.tutor;

    Insert(root, team);
    count1++;   // 每次添加队伍信息后,记录数量加 1
    cout << "成功添加队伍信息!\n";
}

void Delete() {
    if (root == nullptr) {
        cout << "暂无队伍信息!\n";
        return;
    }
    cout << "请输入要删除的参赛队编号:\n";
    string id;
    cin >> id;
    TreeNode* node = root;
    while (node != nullptr && node->data.id != id) {
        if (id < node->data.id) {
            node = node->left;
        }
        else {
            node = node->right;
        }
    }
    if (node == nullptr) {
        cout << "未找到对应编号的队伍信息!\n";
        return;
    }
    if (node->left == nullptr) {  // 如果只有右子树或没有子节点,则直接将右子树或空指针赋给当前节点的父节点指针
        root = node->right;
    }
    else if (node->right == nullptr) {  // 如果只有左子树,则直接将左子树赋给当前节点的父节点指针
        root = node->left;
    }
    else {  // 如果被删除节点有两个子节点
        TreeNode* parent = nullptr;
        TreeNode* minNode = node->right;   // 查找右子树中的最小节点
        while (minNode->left != nullptr) {
            parent = minNode;
            minNode = minNode->left;
        }
        if (parent != nullptr) {
            parent->left = minNode->right;   // 将右子树中的最小节点的右子树赋给其父节点的左指针
            minNode->right = node->right;    // 将被删除节点的右子树赋给最小节点的右指针
        }
        else {
            root = minNode;     // 如果被删除节点的右子树没有左子树,则直接将右子树赋给当前节点的父节点指针
            minNode->left = node->left;   // 将被删除节点的左子树赋给最小节点的左指针
        }
        delete node;   // 释放被删除节点的内存空间
        count1--;       // 每次删除队伍信息后,记录数量减 1
        cout << "成功删除队伍信息!\n";
    }
}
    void Update() {
        if (root == nullptr) {
            cout << "暂无队伍信息!\n";
            return;
        }
        cout << "请输入要修改的参赛队编号:\n";
        string id;
        cin >> id;
        TreeNode* node = root;
        while (node != nullptr && node->data.id != id) {
            if (id < node->data.id) {
                node = node->left;
            }
            else {
                node = node->right;
            }
        }
        if (node == nullptr) {
            cout << "未找到对应编号的队伍信息!\n";
            return;
        }

        cout << "\n参赛队编号:" << node->data.id << "\n"
            << "参赛作品名称:" << node->data.name << "\n"
            << "参赛学校:" << node->data.school << "\n"
            << "参赛类别:" << node->data.type << "\n"
            << "参赛学生姓名:" << node->data.member << "\n"
            << "指导老师姓名:" << node->data.tutor << endl;

        cout << "请选择要修改的信息:\n1.参赛作品名称\n2.参赛学校\n3.参赛类别\n4.参赛学生姓名\n5.指导老师姓名\n";
        int choice;
        cin >> choice;

        switch (choice)
        {
        case 1:
            cout << "请输入新的参赛作品名称:\n";
            cin >> node->data.name;
            break;
        case 2:
            cout << "请输入新的参赛学校:\n";
            cin >> node->data.school;
            break;
        case 3:
            cout << "请输入新的参赛类别:\n";
            cin >> node->data.type;
            break;
        case 4:
            cout << "请输入新的参赛学生姓名:\n";
            cin >> node->data.member;
            break;
        case 5:
            cout << "请输入新的指导老师姓名:\n";
            cin >> node->data.tutor;
            break;
        default:
            cout << "输入错误!\n";
            break;
        }

        cout << "\n参赛队编号:" << node->data.id << "\n"
            << "参赛作品名称:" << node->data.name << "\n"
            << "参赛学校:" << node->data.school << "\n"
            << "参赛类别:" << node->data.type << "\n"
            << "参赛学生姓名:" << node->data.member << "\n"
            << "指导老师姓名:" << node->data.tutor << endl;

        cout << "成功修改队伍信息!\n";
    }

    void Write() {
        ofstream o;
        o.open("team.txt");
        if (!root) {
            cout << "暂无队伍信息!\n";
            return;
        }
        vector<TreeNode*> nodeStack;  // 定义一个栈来存储遍历过的节点
        nodeStack.push_back(root);
        while (!nodeStack.empty()) {
            TreeNode* node = nodeStack.back();
            nodeStack.pop_back();
            if (node != nullptr) {
                o << node->data.id << "#" << node->data.name << "#" << node->data.school << "#" << node->data.type << "#" << node->data.member << "#" << node->data.tutor << "\n";
                nodeStack.push_back(node->right);
                nodeStack.push_back(node->left); //实现先遍历右子树再遍历左子树
            }
        }
        cout << "成功写入 " << count1 << " 条队伍信息!\n";
        o.close();
    }

    void call(int treeSize) {
        if (root == nullptr) {
            cout << "暂无队伍信息!\n";
            return;
        }
        // 定义一个map,用来存储赛事类别和对应的参赛队伍
        map<string, vector<TreeNode*>> teamMap;
        vector<TreeNode*> nodeStack;  // 定义一个栈来存储遍历过的节点
        nodeStack.push_back(root);
        while (!nodeStack.empty()) {
            TreeNode* node = nodeStack.back();
            nodeStack.pop_back();
            if (node != nullptr) {
                teamMap[node->data.type].push_back(node);  // 根据赛事类别将参赛队伍添加到对应的vector中
                nodeStack.push_back(node->right);
                nodeStack.push_back(node->left);
            }
        }

        srand((unsigned int)time(NULL));  // 初始化随机数种子
        int count = 0;
        while (count < treeSize) {
            for (int i = 1; i <= 9; i++) {   // 循环九次,表示九个决赛室
                cout << "=======================\n";
                cout << "第 " << i << " 个决赛室叫号:\n";

                // 随机选择一支队伍
                bool found = false;
                for (map<string, vector<TreeNode*>>::iterator it = teamMap.begin(); it != teamMap.end(); ++it) {
                    vector<TreeNode*> teamVec = it->second;
                    if (!teamVec.empty()) {   // 如果当前类别的队伍还有剩余,则从中选择一个
                        int teamIndex = rand() % teamVec.size();  // 随机选择一个队伍
                        TreeNode* teamNode = teamVec[teamIndex];

                        cout << "参赛队编号:" << teamNode->data.id << "\n"
                            << "参赛作品名称:" << teamNode->data.name << "\n"
                            << "参赛学校:" << teamNode->data.school << "\n"
                            << "参赛类别:" << teamNode->data.type << "\n"
                            << "参赛学生姓名:" << teamNode->data.member << "\n"
                            << "指导老师姓名:" << teamNode->data.tutor << endl;

                        // 删除被选择的参赛队伍,避免重复叫号
                        teamVec.erase(teamVec.begin() + teamIndex);
                        teamMap[it->first] = teamVec;
                        count++;
                        found = true;
                        break;
                    }
                }
                if (!found) {   // 如果所有类别的队伍都已经叫完,则直接退出循环
                    cout << "所有队伍已经叫完!\n";
                    return;
                }
            }
        }
    }

    unordered_map<int, vector<pair<int, int>>> graph = {
    {1, {{2, 150}, {4, 250}}},
    {2, {{1, 150}, {3, 100}, {4, 200}}},
    {3, {{2, 100}, {4, 130},{6,120}}},
    {4, {{1, 250}, {2, 200}, {3, 150},{5,100},{9,300}}},
    {5, {{4, 100}, {6, 150} ,{7,100}}},
    {6, {{3, 120}, {5, 150},{8,90}}},
    {7, {{5, 100}, {9, 80},{10,100}}},
    {8, {{6, 90}, {10, 200}}},
    {9, {{4, 300}, {7, 80},{10,40}}},
    {10, {{7, 100}, {8, 200}, {9, 40}}}
    };

    void navigate(int start, int end) //Dijkstra 算法
    {
        int n = graph.size();
        unordered_map<int, int> dist; // 距离数组存储起点到每个节点的最短距离
        priority_queue<pair<int, int>> pq; // 小根堆存储未遍历的节点
        pq.push(make_pair(0, start)); // 将起点加入小根堆

        for (int i = 1; i <= n; ++i) {
            dist[i] = INT_MAX;
        }
        dist[start] = 0; // 初始化起点距离为0

        while (!pq.empty()) {
            int node = pq.top().second;
            pq.pop();

            for (auto neighbor : graph[node]) {
                int nextNode = neighbor.first;
                int weight = neighbor.second;
                int newDistance = dist[node] + weight; // 计算新距离

                if (dist.find(nextNode) == dist.end() || dist[nextNode] > newDistance) {
                    dist[nextNode] = newDistance;
                    pq.push(make_pair(-newDistance, nextNode));
                }
            }
        }

        // 输出最短路径
        if (dist.find(end) == dist.end()) {
            cout << "无法到达终点!\n";
        }
        else {
            vector<int> path; // 存储路径上的节点
            int node = end;
            while (node != start) {
                path.push_back(node);
                for (auto neighbor : graph[node]) {
                    int prevNode = neighbor.first;
                    int weight = neighbor.second;
                    if (dist[node] == dist[prevNode] + weight) {
                        node = prevNode;
                        break;
                    }
                }
            }
            path.push_back(start);
            reverse(path.begin(), path.end());
            cout << "最短路径为:" << dist[end] <<"米" << ",路径为:" << path[0];
            for (int i = 1; i < path.size(); ++i) {
                cout << " -> " << path[i];
            }
            cout << endl;
        }
    }



    int main() {
        int choice;
        do {
            cout << "\n==========================\n";
            cout << "欢迎使用参赛队伍信息管理系统\n";
            cout << "--------------------------\n";
            cout << "1.读取参赛队伍信息\n";
            cout << "2.查找参赛队伍信息\n";
            cout << "3.添加参赛队伍信息\n";
            cout << "4.删除参赛队伍信息\n";
            cout << "5.修改参赛队伍信息\n";
            cout << "6.输出所有参赛队伍信息\n";
            cout << "7.保存参赛队伍信息\n";
            cout << "8.对所有参赛队伍进行叫号\n";
            cout << "9.导航\n";
            cout << "10.退出\n";
            cout << "--------------------------\n";
            cout << "请选择:";
            cin >> choice;
            cout << "==========================\n";
            switch (choice)
            {
            case 1:
                Read();
                break;
            case 2:
                Search();
                break;
            case 3:
                Insert();
                break;
            case 4:
                Delete();
                break;
            case 5:
                Update();
                break;
            case 6:
                InorderTraversal(root);
                break;
            case 7:
                Write();
                break;
            case 8:
                int num;
                cout << "请输入想要叫号的队伍数量:" << endl;
                cin >> num;
                call(num);
                break;
            case 9:
                int start, end;
                cout << "以下是所有的比赛场地:" << endl;
                cout << "--------------------------\n";
                cout << "1.3号组团" << endl;
                cout << "2.西苑食堂" << endl;
                cout << "3.明德园" << endl;
                cout << "4.文体中心" << endl;
                cout << "5.文心园" << endl;
                cout << "6.文理大楼" << endl;
                cout << "7.求索园" << endl;
                cout << "8.梦溪园" << endl;
                cout << "9.东苑食堂" << endl;
                cout << "10.图书馆" << endl;
                cout << "--------------------------\n";
                cout << "请输入起点和终点:\n";
                cin >> start >> end;
                navigate(start, end);
                break;
            case 10:
                cout << "感谢使用本系统,再见!\n";
                exit(0);   // 退出程序
                break;
            default:
                cout << "输入错误!\n";
                break;
            }
        } while (choice != 10);

        return 0;
    }

 

1.实验内容: 1) 建立学生档案管理的数据结构和存储结构; 2) 完成学生档案管理数据的基本操作; 3) 为提高管理效率,尝试设计较好的面向应用的查找存储结构,如二叉排序树。 2.实验任务: 设计一个学生档案管理信息系统,管理的学生信息包括学号、姓名、性别、高数成绩、英语成绩、大学物理成绩;要求可对学生档案信息进行浏览、增加、修改、删除和查找操作;能够依据不同的检索条件进行查找. 2 隐式图的搜索问题 1. 实验内容: 1) 对九宫重排问题,建立图的启发式搜索求解问题的方法; 2) 编写九宫重排问题的启发式搜索求解程序。 2. 实验任务: 在3х3九宫棋盘中,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘的布局。根据给定初始布局和目标布局,求解如何移动棋子才能从初始布局到达目标布局,找到一种最少步骤的移动方法。 3 可视化界面的文本文件操作 1. 实验内容: 1).通过对可视化开发环境的实用,实现对文本文件编辑器的设计。 2).通过键盘实现对文本文件进行创建、插入、删除、修改、存储等操作。 2. 实验任务: 设计一个具有可视化界面的全文本编辑器,通过对键盘操作可实现对文本进行显示、插入、修改、删除、查找、存储等操作。实现全文本编辑器的基本功能。具体要求如下:  具有图形菜单界面;  能正确显示文本总行数。(行数不少于5行,每行字符数不少于80个字符);  可正确读取,保存文本;  能实现简单的文本处理功能  查找:查找文本中的字符串,显示其出现的行数,列数及总共出现次数  替换(等长,不等长):对文本中的文本实现等长及不等长替换  插入(插串,文本块的插入):插入一行或在具体行号列号处插入文本  删除:删除一行,删除某一行、某列,定长的内容
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值