数据结构课设

 


 

1问题定义

对参赛队的基本信息进行存储和修改

2问题分析

要考虑如何去对参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项;包括增加、删除、修改参赛队伍的信息。这需要使用一个数据结构来进行储存和进行相应的操作。我使用了向量来储存数据。

3概要设计

数据结构设计

结点信息的数据结构:结构体——tea用于存储队伍的的详细信息,如参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师。

struct Team {
    string id; // 参赛队编号
    string name; // 参赛作品名称
    string school; // 参赛学校
    string category; // 赛事类别
    string members; // 参赛者
    string teacher; // 指导老师
};

这里所有的数据都使用字符串来存储,解释一下为什么不用int来存储。

考虑到后面对文本的读取,第一行的文本如下图

第一行的编号为字符串形式,若直接使用try catch进行抛出处理,会导致后文中的对数据进行删改增加后的数据产生确实所以定义id为string类型。

 这是对文本中水平制表符的过滤函数trim,对字符串进行首尾的查询,如果存在水平制表符则删除首尾的水平制表符,并返回一个新的字符串。如果输入字符串中只包含制表符,则将其清空并返回一个空字符串。

std::string trim(std::string s) {
    if (!s.empty()) {
        auto start = s.find_first_not_of("\t");
        auto end = s.find_last_not_of("\t");
        if (start == std::string::npos) {
            s.clear();
        }
        else {
            s = s.substr(start, end - start + 1);
        }
    }
    return s;
}

readTeamFromFile是向量对文件的读取的函数
值得注意的是由于对id的读取是分两种情况的,所以使用了 bool firstLine = true;来判别读取的是否为第一行,若为第一行直接存储,其他行则先将它转换为int再转换为字符串。
team 对象的 id 成员变量的类型是 std::string,而 field 的类型也是 std::string。如果直接将 field 赋值给 team 对象的 id 成员变量,编译器会报错,提示类型不匹配。因此,需要将 field 先转换为整型 int,然后再将其转换为字符串类型,并将其赋值给 team 对象的 id 成员变量。

vector<Team> readTeamsFromFile(string filename) {
    vector<Team> teams;
    ifstream fin(filename);
    if (fin.is_open()) {
        string line;
        bool firstLine = true;
        while (getline(fin, line)) {
            Team team;
            int pos = 0;
            for (int i = 0; i < 6; i++) {
                int next = line.find('#', pos);
                string field = line.substr(pos, next - pos);

                field = trim(field); // 调用 trim 函数修剪字段内容

                if (i == 0) {
                    if (firstLine) {
                        team.id = field;
                        firstLine = false;
                    }
                    else {
                        team.id = to_string(stoi(field));
                    }
                }
                else if (i == 1) {
                    team.name = field;
                }
                else if (i == 2) {
                    team.school = field;
                }
                else if (i == 3) {
                    team.category = field;
                }
                else if (i == 4) {
                    team.members = field;
                }
                else if (i == 5) {
                    team.teacher = field;
                }
                pos = next + 1;
            }
            teams.push_back(team);
        }
        fin.close();
    }
    else {
        cout << "无法打开文件 " << filename << endl;
    }
    return teams;
}

1问题定义

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

2问题分析

如何建立二叉排序树,输入得到二叉排序树的节点,所有节点的深度和节点个数,二叉排序树的asl=所有节点的深度/节点个数。

通过对二叉排序树的节点进行遍历,得到所有节点的深度和节点个数

3概要设计

数据结构设计

参赛队的数据结构:定义二叉排序
 

// 定义二叉排序树节点结构体
struct Node {
    string id; // 参赛队编号
    Team team; // 参赛队信息
    Node* left; // 左子节点指针
    Node* right; // 右子节点指针
};

 对于二叉排序树的构建

1、就是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2、若它的右子树不空,则右子树上所有节点的值均大于其根节点的值。
3、换句话说就是:任何节点的键值一定大于其左子树中的每一个节点的键值,并小于其右子树中的每一个节点的键值。

// 构建二叉排序树
Node* buildBST(vector<Team>& teams) {
    Node* root = nullptr; // 创建根节点指针,初始化为空
    for (int i = 1; i < teams.size(); i++) { // 循环遍历向量中的每个元素
        Node* node = new Node; // 创建一个新节点
        node->id = teams[i].id; // 设置节点的编号
        node->team = teams[i]; // 设置节点的参赛队信息
        node->left = nullptr; // 初始化左子节点指针为空
        node->right = nullptr; // 初始化右子节点指针为空
        if (root == nullptr) { // 如果根节点为空,将新节点设置为根节点
            root = node;
        }
        else { // 否则,将新节点插入到二叉排序树中
            Node* p = root; // 创建一个指针p,指向根节点
            while (true) { // 不断循环,直到找到合适的插入位置
                if (node->id < p->id) { // 如果要插入的节点编号小于当前节点编号
                    if (p->left == nullptr) { // 如果当前节点的左子节点为空,将新节点插入到左子节点
                        p->left = node;
                        break;
                    }
                    else { // 否则,继续向左子树查找
                        p = p->left;
                    }
                }
                else { // 如果要插入的节点编号大于等于当前节点编号
                    if (p->right == nullptr) { // 如果当前节点的右子节点为空,将新节点插入到右子节点
                        p->right = node;
                        break;
                    }
                    else { // 否则,继续向右子树查找
                        p = p->right;
                    }
                }
            }
        }
    }
    return root; // 返回根节点指针
}

但由于上文中对文件的读取,把id为参赛队伍编号也读取进内存,会导致节点数多出一个,对此我在上述二叉树建立的函数中,我将遍历元素i,,从1开始。 

二叉树查找函数

bool queryTeam(Node* root, string id) {
    if (root == nullptr) { // 如果根节点为空,说明查找失败
        cout << "查找失败!" << endl;
        return false;
    }
    if (root->id == id) { // 如果找到了指定编号的参赛队信息
        Team team = root->team; // 获取当前参赛队信息
        // 输出当前参赛队信息到屏幕上
        cout << "参赛作品名称:" << team.name << endl;
        cout << "参赛学校:" << team.school << endl;
        cout << "赛事类别:" << team.category << endl;
        cout << "参赛者:" << team.members << endl;
        cout << "指导老师:" << team.teacher << endl;
        return true; // 返回成功标志
    }
    else if (id < root->id) { // 如果要查找的编号小于当前节点编号,向左子树查找
        return queryTeam(root->left, id);
    }
    else { // 如果要查找的编号大于当前节点编号,向右子树查找

        return queryTeam(root->right, id);
    }
}

首先获取指定编号的参赛队信息,若成功输出相关信息。否则失败,若编号小于当前节点编号,向左字数查找,递归。否则就是大于当前节点编号,向右字数查找,递归。
对二叉树的遍历函数
 

void traverseBST(Node* root, int depth, int& count, int& depthSum) {
    if (root == nullptr) { // 如果根节点为空,直接返回
        return;
    }
    count++; // 节点个数加1
    depthSum += depth; // 深度之和加上当前节点的深度
    traverseBST(root->left, depth + 1, count, depthSum); // 遍历左子树
    traverseBST(root->right, depth + 1, count, depthSum); // 遍历右子树

通过遍历的方法得到不同层的节点数和深度,相加得到节点深度总和,深度总和。
 

1、问题定义

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

2问题分析

使用什么排序来输出参赛队编号

因为数据量较大,采用归并排序的方法,来排序。
(19条消息) 排序——归并排序(Merge sort)_努力的老周的博客-CSDN博客

3概要设计

排序函数如下

void merge(vector<Team>& teams, int left, int mid, int right) {
    int i = left, j = mid + 1, k = 0;
    vector<Team> temp(right - left + 1);

    while (i <= mid && j <= right) {
        if (teams[i].id <= teams[j].id) {
            temp[k++] = teams[i++];
        }
        else {
            temp[k++] = teams[j++];
        }
    }

    while (i <= mid) {
        temp[k++] = teams[i++];
    }

    while (j <= right) {
        temp[k++] = teams[j++];
    }

    for (i = 0; i < k; i++) {
        teams[left + i] = temp[i];
    }
}

void mergeSort(vector<Team>& teams, int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        mergeSort(teams, left, mid);
        mergeSort(teams, mid + 1, right);
        merge(teams, left, mid, right);
    }
}

增删修改的函数如下 

void queryTeam1(vector<Team>& teams) {
    string category;
    cout << "请输入要查询的赛事类别:" << endl;
    cin >> category;

    // 归并排序
    mergeSort(teams, 0, teams.size() - 1);

    // 输出排序后的参赛队信息
    for (int i = 0; i < teams.size(); i++) {
        if (teams[i].category == category) {
            Team team = teams[i];
            cout << "编号:" << team.id << endl;
            cout << "作品名称:" << team.name << endl;
            cout << "学校:" << team.school << endl;
            cout << "类别:" << team.category << endl;
            cout << "参赛者:" << team.members << endl;
            cout << "指导老师:" << team.teacher << endl;
        }
    }
}
void addTeam(vector<Team>& teams) {
    Team team;
    cout << "请输入参赛队伍信息:" << endl;
    cout << "编号:";
    cin >> team.id;
    cout << "作品名称:";
    cin >> team.name;
    cout << "学校:";
    cin >> team.school;
    cout << "类别:";
    cin >> team.category;
    cout << "参赛者:";
    cin >> team.members;
    cout << "指导老师:";
    cin >> team.teacher;
    teams.push_back(team);
    cout << "添加成功!" << endl;
}

// 删除参赛队伍信息
void deleteTeam(vector<Team>& teams) {
    int id;
    cout << "请输入要删除的参赛队伍编号:";
    cin >> id;
    for (auto it = teams.begin(); it != teams.end(); it++) {
        if (it->id == to_string(id)) {
            teams.erase(it);
            cout << "删除成功!" << endl;
            return;
        }
    }
    cout << "未找到该参赛队伍!" << endl;
}

// 修改参赛队伍信息
void modifyTeam(vector<Team>& teams) {
    int id;
    cout << "请输入要修改的参赛队伍编号:";
    cin >> id;
    for (auto& team : teams) {
        if (team.id == to_string(id)) {
            cout << "请输入新的参赛队伍信息:" << endl;
            cout << "作品名称:";
            cin >> team.name;
            cout << "学校:";
            cin >> team.school;
            cout << "类别:";
            cin >> team.category;
            cout << "参赛者:";
            cin >> team.members;
            cout << "指导老师:";
            cin >> team.teacher;
            return;
        }
    }
    cout << "未找到该参赛队伍!" << endl;
}

// 将参赛队伍信息写入文件
void writeToFile(const vector<Team>& teams, const string& filename) {
    ofstream outfile(filename);
    if (outfile.is_open()) {
        for (const auto& team : teams) {
            outfile << team.id << "\t#\t" << team.name << "\t#\t" << team.school << "\t#\t" << team.category << "\t#\t" << team.members << "\t#\t" << team.teacher << endl;
        }
        outfile.close();
        cout << "参赛队伍信息已写入文件 " << filename << " 中!" << endl;
    }
    else {
        cout << "无法打开文件 " << filename << "!" << endl;
    }
}

void mergeSort(vector<Team>& teams, int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        mergeSort(teams, left, mid);
        mergeSort(teams, mid + 1, right);
        merge(teams, left, mid, right);
    }
}


 

1问题定义

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

2问题分析

将9个赛事类别加入不同的rooms[]中,,最后按序输出。

3概要设计

数据结构设计

结点信息的数据结构:结构体——Room  用于存储决赛室的编号和参赛队列。

// 定义全局变量
const int NUM_ROOMS = 9; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组

定义全局变量方便后面存储
 

// 定义全局变量
const int NUM_ROOMS = 9; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组

 将不同类别的赛事存入不同的数组

void add_team(vector<Team>& teams)
{
    // 定义需要用到的变量和常量
    char strs1[3][20] = { {"大数据实践"} };
    char strs2[4][30] = { {"信息图形设计"}, {"动态信息影像(MG动画)"}, {"交互信息设计"}, {"数据可视化"} };
    char strs3[4][30] = { {"人工智能实践赛"} };
    char strs4[5][30] = { {"Web应用与开发"}, {"管理信息系统 "}, {"算法设计与应用"}, {"移动应用开发"} };
    char strs5[5][30] = { {"医药卫生"}, {"数字生活"}, {"运动健身 "}, {"城市管理 "}, {"行业应用"} };
    char strs6[5][30] = { {"动画"}, {"纪录片"}, {"数字短片"}, {"微电影 "}, {"新媒体漫画"} };
    char strs7[5][30] = { {"产品设计"}, {"环境设计"}, {"平面设计"} };
    char strs8[5][30] = { {"交互媒体设计"}, {"游戏设计"}, {"虚拟现实VR与增强现实AR"} };
    char strs9[5][50] = { {"汉语言文学"}, {"计算机基础与应用类课程微课"}, {"虚拟实验平台"}, {"中、小学数学或自然科学课程微课"} };

    // 将strs存入一个vector中,方便遍历
    vector<const char*> strs;
    strs.insert(strs.end(), strs1, strs1 + 1);
    strs.insert(strs.end(), strs2, strs2 + 4);
    strs.insert(strs.end(), strs3, strs3 + 1);
    strs.insert(strs.end(), strs4, strs4 + 4);
    strs.insert(strs.end(), strs5, strs5 + 5);
    strs.insert(strs.end(), strs6, strs6 + 5);
    strs.insert(strs.end(), strs7, strs7 + 3);
    strs.insert(strs.end(), strs8, strs8 + 3);
    strs.insert(strs.end(), strs9, strs9 + 4);

    // 定义队列
    queue<Team> q1, q2, q3, q4, q5, q6, q7, q8, q9;
    mergeSort(teams, 0, teams.size() - 1);
    // 遍历teams,将相同category的team加入相应的队列
    for (int i = 0; i < teams.size(); ++i) {
        const char* category = teams[i].category.c_str();
        for (int j = 0; j < strs.size(); ++j) {
            if (strcmp(category, strs[j]) == 0) {
              if (j==0)
                    q1.push(teams[i]);
              else if(j>0 && j<=4)
                    q2.push(teams[i]);
              else if (j > 4 && j <=5 )
                    q3.push(teams[i]);
              else if (j > 5 && j <= 9)
                    q4.push(teams[i]);
              else if (j > 9 && j <= 14)
                    q5.push(teams[i]);
              else if (j > 14 && j <= 19)
                    q6.push(teams[i]);
              else if (j > 19 && j <= 22)
                    q7.push(teams[i]);
              else if (j > 22 && j <= 25)
                    q8.push(teams[i]);
              else if (j > 25 && j <=29)
                    q9.push(teams[i]);
            }
        }
    }

    // 将队列存入全局变量的rooms数组中
    rooms[0] = { 1, q1 };
    rooms[1] = { 2, q2 };
    rooms[2] = { 3, q3 };
    rooms[3] = { 4, q4 };
    rooms[4] = { 5, q5 };
    rooms[5] = { 6, q6 };
    rooms[6] = { 7, q7 };
    rooms[7] = { 8, q8 };
    rooms[8] = { 9, q9 };
}

将九类的赛事分别定义,如果符合一类赛事中任一一个,将其加入相应的队列。最后将决赛房间号与队列绑定。 

 对叫号系统的模拟函数

void call_teams() {
    // 循环遍历所有决赛室
    for (int i = 0; i < NUM_ROOMS; ++i) {
        // 当前决赛室
        Room& room = rooms[i];
        // 当前决赛室队列不为空时,循环叫号
        while (!room.teams.empty()) {
            // 输出叫号信息
            cout << "决赛室" << room.id << "请题目为:" << room.teams.front().name << "参赛队进场比赛" << endl;
            // 模拟参赛队进场比赛0.5秒
            this_thread::sleep_for(chrono::milliseconds(5));
            // 弹出队首元素
            room.teams.pop();
        }
    }
}

1问题定义

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

2问题分析

导航是一个无向图的问题,使用邻接表来存储,使用dijkstra算法

3概要设计

数据结构设计

结点信息的数据结构:邻接表

    adjList[1].push_back(make_pair(2, 100)); // 添加从节点 1 到节点 2 权值为 100 的边
    adjList[1].push_back(make_pair(4, 200)); // 添加从节点 1 到节点 4 权值为 200 的边
    adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
    adjList[2].push_back(make_pair(4, 150)); // 添加从节点 2 到节点 4 权值为 150 的边
    adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
    adjList[3].push_back(make_pair(2, 80)); // 添加从节点 3 到节点 2 权值为 80 的边
    adjList[3].push_back(make_pair(5, 120)); // 添加从节点 3 到节点 5 权值为 120 的边
    adjList[3].push_back(make_pair(6, 110)); // 添加从节点 3 到节点 6 权值为 110 的边
    adjList[4].push_back(make_pair(1, 200)); // 添加从节点 4 到节点 1 权值为 200 的边
    adjList[4].push_back(make_pair(2, 150)); // 添加从节点 4 到节点 2 权值为 150 的边
    adjList[4].push_back(make_pair(5, 50)); // 添加从节点 4 到节点 5 权值为 50 的边
    adjList[5].push_back(make_pair(3, 120)); // 添加从节点 5 到节点 3 权值为 120 的边
    adjList[5].push_back(make_pair(4, 50)); // 添加从节点 5 到节点 4 权值为 50 的边
    adjList[5].push_back(make_pair(8, 150)); // 添加从节点 5 到节点 8 权值为 150 的边
    adjList[5].push_back(make_pair(9, 230)); // 添加从节点 5 到节点 9 权值为 230 的边
    adjList[6].push_back(make_pair(3, 110)); // 添加从节点 6 到节点 3 权值为 110 的边
    adjList[6].push_back(make_pair(7, 80)); // 添加从节点 6 到节点 7 权值为 80 的边
    adjList[6].push_back(make_pair(8, 80)); // 添加从节点 6 到节点 8 权值为 80 的边
    adjList[7].push_back(make_pair(6, 80)); // 添加从节点 7 到节点 6 权值为 80 的边
    adjList[7].push_back(make_pair(10, 100)); // 添加从节点 7 到节点 10 权值为 100 的边
    adjList[8].push_back(make_pair(5, 150)); // 添加从节点 8 到节点 5 权值为 150 的边
    adjList[8].push_back(make_pair(6, 60)); // 添加从节点 8 到节点 6 权值为 60 的边
    adjList[8].push_back(make_pair(9, 90)); // 添加从节点 8 到节点 9 权值为 90 的边
    adjList[8].push_back(make_pair(10, 70)); // 添加从节点 8 到节点 10 权值为 70 的边
    adjList[9].push_back(make_pair(5, 230)); // 添加从节点 9 到节点 5 权值为 230 的边
    adjList[9].push_back(make_pair(8, 90)); // 添加从节点 9 到节点 8 权值为 90 的边
    adjList[9].push_back(make_pair(10, 50)); // 添加从节点 9 到节点 10 权值为 50 的边
    adjList[10].push_back(make_pair(7, 100)); // 添加从节点 10 到节点 7 权值为 100 的边
    adjList[10].push_back(make_pair(8, 70)); // 添加从节点 10 到节点 8 权值为 70 的边
    adjList[10].push_back(make_pair(9, 50)); // 添加从节点 10 到节点 9 权值为 50 的边

dijkstra算法的实现
 

// 定义无穷大常量INF,用于表示路径长度的上限
const int INF = numeric_limits<int>::max();

// Dijkstra算法实现
void dijkstra(vector<vector<pair<int, int>>>& adjList, int start, int end, vector<string>& names, vector<string>& descriptions) {
    int n = adjList.size();

    // 定义距离数组dist和前驱数组prev
    vector<int> dist(n, INF);
    vector<int> prev(n, -1);

    // 将起点的距离设为0
    dist[start] = 0;

    // 定义优先队列pq,用于存储待处理的节点
    // 优先队列中存储节点到起点的距离和节点编号,按距离从小到大排序
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push(make_pair(0, start));

    // 循环处理待处理的节点,直到队列为空
    while (!pq.empty()) {
        // 取出距离起点最近的节点
        int u = pq.top().second;
        pq.pop();

        // 遍历该节点的邻居节点
        for (auto v : adjList[u]) {
            // 计算该邻居节点到起点的距离
            int alt = dist[u] + v.second;

            // 如果新的距离比原来的距离更短,则更新距离和前驱节点
            if (alt < dist[v.first]) {
                dist[v.first] = alt;
                prev[v.first] = u;

                // 将该邻居节点加入优先队列
                pq.push(make_pair(dist[v.first], v.first));
            }
        }
    }

    // 如果终点的距离为无穷大,则表示没有可达路径
    if (dist[end] == INF) {
        cout << "No path found" << endl;
    }
    else {
        // 输出最短路径的长度
        cout << "Shortest path length: " << dist[end] << endl;

        // 输出最短路径的节点序列
        cout << "Path: ";
        vector<int> path;
        int cur = end;
        while (cur != -1) {
            path.push_back(cur);
            cur = prev[cur];
        }
        for (int i = path.size() - 1; i >= 0; i--) {
            cout << names[path[i]] << " ";
        }
        cout << endl;

        // 输出终点的名称和描述
        cout << "Destination: " << names[end] << endl;
        cout << "Description: " << descriptions[end] << endl;
    }
}

Dijkstra算法详解 通俗易懂 - 知乎 (zhihu.com)

完整的代码 
 

#include<iostream>
#include <fstream>
#include <iostream>
#include<queue>
#include<vector>
#include<string>
#include <algorithm>
#include <thread>
#include <chrono>
#include<unordered_map>
using namespace std;
std::string trim(std::string s) {
    if (!s.empty()) {
        auto start = s.find_first_not_of("\t");
        auto end = s.find_last_not_of("\t");
        if (start == std::string::npos) {
            s.clear();
        }
        else {
            s = s.substr(start, end - start + 1);
        }
    }
    return s;
}
struct Team {
    string id; // 参赛队编号
    string name; // 参赛作品名称
    string school; // 参赛学校
    string category; // 赛事类别
    string members; // 参赛者
    string teacher; // 指导老师
};
vector<Team> readTeamsFromFile(string filename) {
    vector<Team> teams;
    ifstream fin(filename);
    if (fin.is_open()) {
        string line;
        bool firstLine = true;
        while (getline(fin, line)) {
            Team team;
            int pos = 0;
            for (int i = 0; i < 6; i++) {
                int next = line.find('#', pos);
                string field = line.substr(pos, next - pos);

                field = trim(field); // 调用 trim 函数修剪字段内容

                if (i == 0) {
                    if (firstLine) {
                        team.id = field;
                        firstLine = false;
                    }
                    else {
                        team.id = to_string(stoi(field));
                    }
                }
                else if (i == 1) {
                    team.name = field;
                }
                else if (i == 2) {
                    team.school = field;
                }
                else if (i == 3) {
                    team.category = field;
                }
                else if (i == 4) {
                    team.members = field;
                }
                else if (i == 5) {
                    team.teacher = field;
                }
                pos = next + 1;
            }
            teams.push_back(team);
        }
        fin.close();
    }
    else {
        cout << "无法打开文件 " << filename << endl;
    }
    return teams;
}
// 定义二叉排序树节点结构体
struct Node {
    string id; // 参赛队编号
    Team team; // 参赛队信息
    Node* left; // 左子节点指针
    Node* right; // 右子节点指针
};

// 二叉排序树查找函数
bool queryTeam(Node* root, string id) {
    if (root == nullptr) { // 如果根节点为空,说明查找失败
        cout << "查找失败!" << endl;
        return false;
    }
    if (root->id == id) { // 如果找到了指定编号的参赛队信息
        Team team = root->team; // 获取当前参赛队信息
        // 输出当前参赛队信息到屏幕上
        cout << "参赛作品名称:" << team.name << endl;
        cout << "参赛学校:" << team.school << endl;
        cout << "赛事类别:" << team.category << endl;
        cout << "参赛者:" << team.members << endl;
        cout << "指导老师:" << team.teacher << endl;
        return true; // 返回成功标志
    }
    else if (id < root->id) { // 如果要查找的编号小于当前节点编号,向左子树查找
        return queryTeam(root->left, id);
    }
    else { // 如果要查找的编号大于当前节点编号,向右子树查找

        return queryTeam(root->right, id);
    }
}

// 构建二叉排序树
Node* buildBST(vector<Team>& teams) {
    Node* root = nullptr; // 创建根节点指针,初始化为空
    for (int i = 1; i < teams.size(); i++) { // 循环遍历向量中的每个元素
        Node* node = new Node; // 创建一个新节点
        node->id = teams[i].id; // 设置节点的编号
        node->team = teams[i]; // 设置节点的参赛队信息
        node->left = nullptr; // 初始化左子节点指针为空
        node->right = nullptr; // 初始化右子节点指针为空
        if (root == nullptr) { // 如果根节点为空,将新节点设置为根节点
            root = node;
        }
        else { // 否则,将新节点插入到二叉排序树中
            Node* p = root; // 创建一个指针p,指向根节点
            while (true) { // 不断循环,直到找到合适的插入位置
                if (node->id < p->id) { // 如果要插入的节点编号小于当前节点编号
                    if (p->left == nullptr) { // 如果当前节点的左子节点为空,将新节点插入到左子节点
                        p->left = node;
                        break;
                    }
                    else { // 否则,继续向左子树查找
                        p = p->left;
                    }
                }
                else { // 如果要插入的节点编号大于等于当前节点编号
                    if (p->right == nullptr) { // 如果当前节点的右子节点为空,将新节点插入到右子节点
                        p->right = node;
                        break;
                    }
                    else { // 否则,继续向右子树查找
                        p = p->right;
                    }
                }
            }
        }
    }
    return root; // 返回根节点指针
}
void traverseBST(Node* root, int depth, int& count, int& depthSum) {
    if (root == nullptr) { // 如果根节点为空,直接返回
        return;
    }
    count++; // 节点个数加1
    depthSum += depth; // 深度之和加上当前节点的深度
    traverseBST(root->left, depth + 1, count, depthSum); // 遍历左子树
    traverseBST(root->right, depth + 1, count, depthSum); // 遍历右子树
}
void merge(vector<Team>& teams, int left, int mid, int right) {
    int i = left, j = mid + 1, k = 0;
    vector<Team> temp(right - left + 1);

    while (i <= mid && j <= right) {
        if (teams[i].id <= teams[j].id) {
            temp[k++] = teams[i++];
        }
        else {
            temp[k++] = teams[j++];
        }
    }

    while (i <= mid) {
        temp[k++] = teams[i++];
    }

    while (j <= right) {
        temp[k++] = teams[j++];
    }

    for (i = 0; i < k; i++) {
        teams[left + i] = temp[i];
    }
}

void mergeSort(vector<Team>& teams, int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        mergeSort(teams, left, mid);
        mergeSort(teams, mid + 1, right);
        merge(teams, left, mid, right);
    }
}

void queryTeam1(vector<Team>& teams) {
    string category;
    cout << "请输入要查询的赛事类别:" << endl;
    cin >> category;

    // 归并排序
    mergeSort(teams, 0, teams.size() - 1);

    // 输出排序后的参赛队信息
    for (int i = 0; i < teams.size(); i++) {
        if (teams[i].category == category) {
            Team team = teams[i];
            cout << "编号:" << team.id << endl;
            cout << "作品名称:" << team.name << endl;
            cout << "学校:" << team.school << endl;
            cout << "类别:" << team.category << endl;
            cout << "参赛者:" << team.members << endl;
            cout << "指导老师:" << team.teacher << endl;
        }
    }
}
void addTeam(vector<Team>& teams) {
    Team team;
    cout << "请输入参赛队伍信息:" << endl;
    cout << "编号:";
    cin >> team.id;
    cout << "作品名称:";
    cin >> team.name;
    cout << "学校:";
    cin >> team.school;
    cout << "类别:";
    cin >> team.category;
    cout << "参赛者:";
    cin >> team.members;
    cout << "指导老师:";
    cin >> team.teacher;
    teams.push_back(team);
    cout << "添加成功!" << endl;
}

// 删除参赛队伍信息
void deleteTeam(vector<Team>& teams) {
    int id;
    cout << "请输入要删除的参赛队伍编号:";
    cin >> id;
    for (auto it = teams.begin(); it != teams.end(); it++) {
        if (it->id == to_string(id)) {
            teams.erase(it);
            cout << "删除成功!" << endl;
            return;
        }
    }
    cout << "未找到该参赛队伍!" << endl;
}

// 修改参赛队伍信息
void modifyTeam(vector<Team>& teams) {
    int id;
    cout << "请输入要修改的参赛队伍编号:";
    cin >> id;
    for (auto& team : teams) {
        if (team.id == to_string(id)) {
            cout << "请输入新的参赛队伍信息:" << endl;
            cout << "作品名称:";
            cin >> team.name;
            cout << "学校:";
            cin >> team.school;
            cout << "类别:";
            cin >> team.category;
            cout << "参赛者:";
            cin >> team.members;
            cout << "指导老师:";
            cin >> team.teacher;
            return;
        }
    }
    cout << "未找到该参赛队伍!" << endl;
}

// 将参赛队伍信息写入文件
void writeToFile(const vector<Team>& teams, const string& filename) {
    ofstream outfile(filename);
    if (outfile.is_open()) {
        for (const auto& team : teams) {
            outfile << team.id << "\t#\t" << team.name << "\t#\t" << team.school << "\t#\t" << team.category << "\t#\t" << team.members << "\t#\t" << team.teacher << endl;
        }
        outfile.close();
        cout << "参赛队伍信息已写入文件 " << filename << " 中!" << endl;
    }
    else {
        cout << "无法打开文件 " << filename << "!" << endl;
    }
}
// 定义决赛室结构体
struct Room {
    int id; // 决赛室编号
    queue<Team> teams; // 参赛队队列
};

// 定义全局变量
const int NUM_ROOMS = 9; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组

void call_teams() {
    // 循环遍历所有决赛室
    for (int i = 0; i < NUM_ROOMS; ++i) {
        // 当前决赛室
        Room& room = rooms[i];
        // 当前决赛室队列不为空时,循环叫号
        while (!room.teams.empty()) {
            // 输出叫号信息
            cout << "决赛室" << room.id << "请题目为:" << room.teams.front().name << "参赛队进场比赛" << endl;
            // 模拟参赛队进场比赛0.5秒
            this_thread::sleep_for(chrono::milliseconds(5));
            // 弹出队首元素
            room.teams.pop();
        }
    }
}

void add_team(vector<Team>& teams)
{
    // 定义需要用到的变量和常量
    char strs1[3][20] = { {"大数据实践"} };
    char strs2[4][30] = { {"信息图形设计"}, {"动态信息影像(MG动画)"}, {"交互信息设计"}, {"数据可视化"} };
    char strs3[4][30] = { {"人工智能实践赛"} };
    char strs4[5][30] = { {"Web应用与开发"}, {"管理信息系统 "}, {"算法设计与应用"}, {"移动应用开发"} };
    char strs5[5][30] = { {"医药卫生"}, {"数字生活"}, {"运动健身 "}, {"城市管理 "}, {"行业应用"} };
    char strs6[5][30] = { {"动画"}, {"纪录片"}, {"数字短片"}, {"微电影 "}, {"新媒体漫画"} };
    char strs7[5][30] = { {"产品设计"}, {"环境设计"}, {"平面设计"} };
    char strs8[5][30] = { {"交互媒体设计"}, {"游戏设计"}, {"虚拟现实VR与增强现实AR"} };
    char strs9[5][50] = { {"汉语言文学"}, {"计算机基础与应用类课程微课"}, {"虚拟实验平台"}, {"中、小学数学或自然科学课程微课"} };

    // 将strs存入一个vector中,方便遍历
    vector<const char*> strs;
    strs.insert(strs.end(), strs1, strs1 + 1);
    strs.insert(strs.end(), strs2, strs2 + 4);
    strs.insert(strs.end(), strs3, strs3 + 1);
    strs.insert(strs.end(), strs4, strs4 + 4);
    strs.insert(strs.end(), strs5, strs5 + 5);
    strs.insert(strs.end(), strs6, strs6 + 5);
    strs.insert(strs.end(), strs7, strs7 + 3);
    strs.insert(strs.end(), strs8, strs8 + 3);
    strs.insert(strs.end(), strs9, strs9 + 4);

    // 定义队列
    queue<Team> q1, q2, q3, q4, q5, q6, q7, q8, q9;
    mergeSort(teams, 0, teams.size() - 1);
    // 遍历teams,将相同category的team加入相应的队列
    for (int i = 0; i < teams.size(); ++i) {
        const char* category = teams[i].category.c_str();
        for (int j = 0; j < strs.size(); ++j) {
            if (strcmp(category, strs[j]) == 0) {
              if (j==0)
                    q1.push(teams[i]);
              else if(j>0 && j<=4)
                    q2.push(teams[i]);
              else if (j > 4 && j <=5 )
                    q3.push(teams[i]);
              else if (j > 5 && j <= 9)
                    q4.push(teams[i]);
              else if (j > 9 && j <= 14)
                    q5.push(teams[i]);
              else if (j > 14 && j <= 19)
                    q6.push(teams[i]);
              else if (j > 19 && j <= 22)
                    q7.push(teams[i]);
              else if (j > 22 && j <= 25)
                    q8.push(teams[i]);
              else if (j > 25 && j <=29)
                    q9.push(teams[i]);
            }
        }
    }

    // 将队列存入全局变量的rooms数组中
    rooms[0] = { 1, q1 };
    rooms[1] = { 2, q2 };
    rooms[2] = { 3, q3 };
    rooms[3] = { 4, q4 };
    rooms[4] = { 5, q5 };
    rooms[5] = { 6, q6 };
    rooms[6] = { 7, q7 };
    rooms[7] = { 8, q8 };
    rooms[8] = { 9, q9 };
}
// 定义无穷大常量INF,用于表示路径长度的上限
const int INF = numeric_limits<int>::max();

// Dijkstra算法实现
void dijkstra(vector<vector<pair<int, int>>>& adjList, int start, int end, vector<string>& names, vector<string>& descriptions) {
    int n = adjList.size();

    // 定义距离数组dist和前驱数组prev
    vector<int> dist(n, INF);
    vector<int> prev(n, -1);

    // 将起点的距离设为0
    dist[start] = 0;

    // 定义优先队列pq,用于存储待处理的节点
    // 优先队列中存储节点到起点的距离和节点编号,按距离从小到大排序
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push(make_pair(0, start));

    // 循环处理待处理的节点,直到队列为空
    while (!pq.empty()) {
        // 取出距离起点最近的节点
        int u = pq.top().second;
        pq.pop();

        // 遍历该节点的邻居节点
        for (auto v : adjList[u]) {
            // 计算该邻居节点到起点的距离
            int alt = dist[u] + v.second;

            // 如果新的距离比原来的距离更短,则更新距离和前驱节点
            if (alt < dist[v.first]) {
                dist[v.first] = alt;
                prev[v.first] = u;

                // 将该邻居节点加入优先队列
                pq.push(make_pair(dist[v.first], v.first));
            }
        }
    }

    // 如果终点的距离为无穷大,则表示没有可达路径
    if (dist[end] == INF) {
        cout << "No path found" << endl;
    }
    else {
        // 输出最短路径的长度
        cout << "Shortest path length: " << dist[end] << endl;

        // 输出最短路径的节点序列
        cout << "Path: ";
        vector<int> path;
        int cur = end;
        while (cur != -1) {
            path.push_back(cur);
            cur = prev[cur];
        }
        for (int i = path.size() - 1; i >= 0; i--) {
            cout << names[path[i]] << " ";
        }
        cout << endl;

        // 输出终点的名称和描述
        cout << "Destination: " << names[end] << endl;
        cout << "Description: " << descriptions[end] << endl;
    }
}
int main()
{
    readTeamsFromFile("C://Users//123//source//repos//ds2//team.txt");
    vector<Team> teams = readTeamsFromFile("C://Users//123//source//repos//ds2//team.txt");
    // 构建二叉排序树
    Node* root = buildBST(teams);
    string filename = "new_teams.txt";
    string id;// 输入要查询的参赛队编号
    int count = 0; // 统计查找次数
    int sum = 0; // 统计查找次数的总和
    int depth = 1;
    int depthSum = 0;
    int n = 20;
    vector<vector<pair<int, int>>> adjList(n); // 创建大小为 n 的邻接表
    vector<string> names = { "", "三号组团", "西苑食堂", "明德楼", "文体中心a", "西操场", "文理大楼", "行政大楼", "求索园", "东苑食堂", "图书馆" };
    vector<string> descriptions = { "", "学生住宿地方原49号楼", "学校西边的食堂", "教学楼,对应校训的笃学明德中的明德", "学生的体育运动中心", "学校靠西边的操场", "江科大最高的一栋楼", "行政教学用地", "花园", "学校西边的食堂", "读书学习的地方" };
    adjList[1].push_back(make_pair(2, 100)); // 添加从节点 1 到节点 2 权值为 100 的边
    adjList[1].push_back(make_pair(4, 200)); // 添加从节点 1 到节点 4 权值为 200 的边
    adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
    adjList[2].push_back(make_pair(4, 150)); // 添加从节点 2 到节点 4 权值为 150 的边
    adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
    adjList[3].push_back(make_pair(2, 80)); // 添加从节点 3 到节点 2 权值为 80 的边
    adjList[3].push_back(make_pair(5, 120)); // 添加从节点 3 到节点 5 权值为 120 的边
    adjList[3].push_back(make_pair(6, 110)); // 添加从节点 3 到节点 6 权值为 110 的边
    adjList[4].push_back(make_pair(1, 200)); // 添加从节点 4 到节点 1 权值为 200 的边
    adjList[4].push_back(make_pair(2, 150)); // 添加从节点 4 到节点 2 权值为 150 的边
    adjList[4].push_back(make_pair(5, 50)); // 添加从节点 4 到节点 5 权值为 50 的边
    adjList[5].push_back(make_pair(3, 120)); // 添加从节点 5 到节点 3 权值为 120 的边
    adjList[5].push_back(make_pair(4, 50)); // 添加从节点 5 到节点 4 权值为 50 的边
    adjList[5].push_back(make_pair(8, 150)); // 添加从节点 5 到节点 8 权值为 150 的边
    adjList[5].push_back(make_pair(9, 230)); // 添加从节点 5 到节点 9 权值为 230 的边
    adjList[6].push_back(make_pair(3, 110)); // 添加从节点 6 到节点 3 权值为 110 的边
    adjList[6].push_back(make_pair(7, 80)); // 添加从节点 6 到节点 7 权值为 80 的边
    adjList[6].push_back(make_pair(8, 60)); // 添加从节点 6 到节点 8 权值为 80 的边
    adjList[7].push_back(make_pair(6, 80)); // 添加从节点 7 到节点 6 权值为 80 的边
    adjList[7].push_back(make_pair(10, 100)); // 添加从节点 7 到节点 10 权值为 100 的边
    adjList[8].push_back(make_pair(5, 150)); // 添加从节点 8 到节点 5 权值为 150 的边
    adjList[8].push_back(make_pair(6, 60)); // 添加从节点 8 到节点 6 权值为 60 的边
    adjList[8].push_back(make_pair(9, 90)); // 添加从节点 8 到节点 9 权值为 90 的边
    adjList[8].push_back(make_pair(10, 70)); // 添加从节点 8 到节点 10 权值为 70 的边
    adjList[9].push_back(make_pair(5, 230)); // 添加从节点 9 到节点 5 权值为 230 的边
    adjList[9].push_back(make_pair(8, 90)); // 添加从节点 9 到节点 8 权值为 90 的边
    adjList[9].push_back(make_pair(10, 50)); // 添加从节点 9 到节点 10 权值为 50 的边
    adjList[10].push_back(make_pair(7, 100)); // 添加从节点 10 到节点 7 权值为 100 的边
    adjList[10].push_back(make_pair(8, 70)); // 添加从节点 10 到节点 8 权值为 70 的边
    adjList[10].push_back(make_pair(9, 50)); // 添加从节点 10 到节点 9 权值为 50 的边
    int m = 0;
    char choice;
    while (true) {
        cout << "请选择操作:" << endl;
        cout << "1. 添加参赛队伍信息" << endl;
        cout << "2. 删除参赛队伍信息" << endl;
        cout << "3. 修改参赛队伍信息" << endl;
        cout << "4. 按编号查询参赛团队 " << endl;
        cout << "5. 按参加类别查询参赛团队" << endl;
        cout << "6. 叫号系统" << endl;
        cout << "7. 导航系统" << endl;
        cout << "8. 退出程序" << endl;
        cout << "请输入操作编号:";
        cin >> choice;
        switch (choice) {
        case '1':
            addTeam(teams);
            break;
        case '2':
            deleteTeam(teams);
            break;
        case '3':
            modifyTeam(teams);
            break;
        case '4':
        { 
            cout << "请输入要查询的参赛队编号:" << endl;
            cin >> id;
            bool found = queryTeam(root, id); // 在二叉排序树中查找指定编号的参赛队信息
            traverseBST(root, depth, count, depthSum);
            if (found) {
                cout << "ASL = depthSum / count" << endl;
                // 输出平均查找长度ASL
                double ASL = (double)depthSum / count;
                cout << count;
                cout << "查找成功!" << endl;
                cout << "平均查找长度ASL:" << ASL << endl;
            }
            else {
                cout << "查找失败!" << endl;
            }
            break; }
        case '5':
            queryTeam1(teams);
            break;
        case '6':
            add_team(teams);
            call_teams();
            break;
        case '7':
        for (int i = 0; i < n; i++) {
            m += adjList[i].size();
        }
        cout << "The number of edges is: " << m << endl;
        cout << "编号从1开始到10分别是1:三号组团, 2:西苑食堂,3: 明德楼, 4:文体中心a, 5:西操场, 6:文理大楼, 7:行政大楼, 8:求索园, 9:东苑食堂,10: 图书馆" << endl;
        cout << "输入起始序号和终点序号" << endl;
        int start, end;
        cin >> start >> end;
        if (start < 0 || start >= n || end < 0 || end >= n) {
            cout << "Invalid input" << endl;
            return 0;
        }
        dijkstra(adjList, start, end, names, descriptions); 
            break;
        case '8':
            writeToFile(teams, filename);
            return 0;
        default:
            cout << "无效的操作编号,请重新输入!" << endl;
            break;
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值