数据结构项目设计
目錄
項目1:計算機設計大賽賽事統計
一、設計主要要求
【問題描述】
【基本要求】
【設計要求】
【測試數據】
【實現提示】
二.問題分析和任務定義
三.邏輯設計
【運行時存儲結構】
【文件中存儲格式】
【主要功能函數】
【調用關系圖】
【流程圖】
四、物理設計
(1)Team類結構
(2)School類結構?
(3)Contest類結構
(4)其他數據結構
(5)文件讀寫
(6)find函數
(7)print函數
(8)insert函數
(9)界面函數
五、測試數據
?補充
項目2:校園導游咨詢
一、設計主要要求
【問題描述】
【基本要求】
【測試數據】
【實現提示】
二、問題分析和任務定義
三、邏輯設計
【存儲結構】
【查詢景點信息模塊】
【查詢景點路徑模塊】
【調用關系圖】
【流程圖】
四、物理設計
【景點類】
【查詢景點信息】
?【查詢景點路徑】?
【Dijkstra算法】
五、預設數據
【景點地圖】
【拓撲圖】
項目3:算術表達式求解
一、設計主要要求
【問題描述】
【基本要求】
【測試數據】
【實現提示】
二、問題分析和任務定義
三、邏輯設計
【數據結構】
【主要功能函數】
【函數調用關系】
【流程圖】
四、物理設計
【核心算法段】
開發工具
結語
項目1:計算機設計大賽賽事統計
一、設計主要要求
【問題描述】
??參加計算機設計大賽的n個學校編號為1~n,賽事分成m個項目,項目的編號為1~m.比賽獲獎按照得分降序,取前三名,寫一個統計程序產生各種成績單和得分報表。
【基本要求】
1)每個比賽項目至少有10支參賽隊;每個學校最多有6支隊伍參賽;
2)能統計各學校的總分;
3)可以按照學校編號或名稱,學校的總分、各項目的總分排序輸出;
4)可以按學校編號查詢學校某個項目的獲獎情況;可以按項目編號查詢取得前三名的學校;
5)數據存入文件并能隨時查詢
【設計要求】
1)輸入數據形式和范圍:可以輸入學校的名稱,賽事項目的名稱。
2)輸出形式:有中文提示,各學校分數為整數
3)界面要求:交互設計要合理,每個功能可以設立菜單,根據提示,可以完成相關功能的要求。
4)存儲結構:學生自己根據系統功能要求自己設計,但是賽事相關數據要存儲在文件中。
【測試數據】
??要求使用全部合法數據,整體非法數據,局部非法數據。進行程序測試,以保證程序的穩定。
【實現提示】
??假設3<賽事項目數量<=10,學校名稱長度不超過20個字符。每個賽事結束時,將其編號、名稱輸入,并依次輸入參賽學校編號、學校名稱和成績。
二.問題分析和任務定義
本程序需要實現的功能有:合理的存儲、文件存取、用戶界面、增加數據功能、刪減修改數據功能、統計各個學校總分功能、可以按照學校總分輸出成績表、按照學校編號查詢項目獲獎情況。可以分解為以下小模塊:
1.學校信息管理
2.賽事信息管理
3.隊伍報名管理
4.查看獲獎信息
5.總分排行榜
6.獲獎排行榜
7.關于本程序
0.保存并退出
層次可以表示如下
void menu(); //一級界面(主界面) void manageSchool(); //二級界面1:學校信息管理 void manageContest(); //二級界面2:比賽信息管理 void teamRegistration(); //二級界面3:隊伍報名管理 void viewPrize(); //二級界面4:查詢學校獲獎信息 void printScoreRank(); //二級界面5:總分排行榜 void printPrizeRank(); //二級界面6:獲獎排行榜 void printInformation(); //二級界面7:程序信息限制條件注意點:賽事項目數量限制、賽事參賽隊伍最少數量限制,非法輸入處理......
三.邏輯設計
【運行時存儲結構】
(1)Team類
ADT Team Data編號,屬于哪個學校,報名哪個比賽,成績OperationConstructor初始數據:編號,學校,競賽功能:初始化編號、隸屬學校、隸屬競賽,成績默認為0Constructor初始數據:編號,學校,競賽,成績功能:初始化編號、隸屬學校、隸屬競賽,成績getScore前提條件:無輸入:無功能:訪問并返回私有變量成績的數值輸出:成績后置條件:無getNoble前提條件:無輸入:無功能:訪問并返回私有變量編號的數值輸出:編號后置條件:無getSchool前提條件:無輸入:無功能:返回隸屬學校的數值輸出:隸屬學校的編號后置條件:無getContest前提條件:無輸入:無功能:返回隸屬競賽的數值輸出:隸屬競賽的編號后置條件:無setScore前提條件:無輸入:要設置的成績功能:設置私有變量成績輸出:無后置條件:無 endADT(2)School
ADT School {Data編號,名稱,隊伍數量,隊伍編號數組,總成績OperationConstructor初始數據:編號,學校名稱功能:初始化編號、學校名稱addTeam前提條件:隊伍未滿輸入:隊伍編號功能:將該編號的隊伍加入學校的隊伍數組內,并將隊伍數量+1輸出:無后置條件:無getNoble前提條件:無輸入:無功能:訪問并返回私有變量編號的數值輸出:編號后置條件:無getName前提條件:無輸入:無功能:返回學校的名稱輸出:學校名字后置條件:無getNum前提條件:無輸入:無功能:返回下轄隊伍數量輸出:隊伍數量后置條件:無getNum前提條件:下標<隊伍數量輸入:下標功能:返回下標對應的隊伍編號輸出:下標的隊伍編號后置條件:無Sum前提條件:無輸入:無功能:計算隊伍的總分輸出:無后置條件:無getSum前提條件:已經調用過Sum計算總分輸入:無功能:返回計算好的隊伍總分輸出:總分后置條件:無 endADT(3)Contest類
ADT School {Data編號,名稱,隊伍數量,參賽隊伍編號數組,是否結束標志OperationConstructor初始數據:編號,競賽名稱功能:初始化編號、競賽名稱addTeam前提條件:無輸入:隊伍編號功能:將該編號的隊伍加入競賽的隊伍數組內,并將隊伍數量+1輸出:無后置條件:無getNoble前提條件:無輸入:無功能:訪問并返回私有變量編號的數值輸出:編號后置條件:無getName前提條件:無輸入:無功能:返回競賽的名稱輸出:學校名字后置條件:無getNum前提條件:無輸入:無功能:返回報名參加的隊伍數量輸出:隊伍數量后置條件:無getNum前提條件:下標<隊伍數量輸入:下標功能:返回下標對應的隊伍編號輸出:下標的隊伍編號后置條件:無rank前提條件:已調用過finish函數輸入:無功能:將隊伍按照分數進行排序輸出:無后置條件:無finish前提條件:隊伍數>=10,并都已打分輸入:無功能:將比賽狀態設置為完成輸出:無后置條件:無isFinished前提條件:無輸入:無功能:返回比賽是否完成輸出:比賽完成與否后置條件:無 endADT私有變量:賽事編號、賽事名稱、含有隊伍數、還有隊伍編號(數組)等。
公有函數:構造函數、增加隊伍函數、排序函數、輸出獲獎信息函數等。
(4)teams數組、schools數組、contest數組
用標準容器vector存儲,基本邏輯為按照學校編號保持有序(便于插入、查詢時減小時間復雜度)
【文件中存儲格式】
第一行三個數A,B,C分別表示:學校個數、賽事個數、隊伍數量。
接下來A行:編號、校名。
接下來B行:編號、賽事狀態(結束與否)、賽事名。
接下來C行:編號、參加賽事編號、隸屬學校編號、分數。
【主要功能函數】
int findSchool(int noble){ //功能函數1:尋找學校,返回下標 int findContest(int noble){ //功能函數2:尋找賽事,返回下標 int findTeam(int noble){ //功能函數3:找到編號為noble的隊伍在容器中的下標,找不到返回-1 void printContestList(){ //功能函數4:輸出比賽列表 int MaxOfTeamNoble(){ //功能函數5:返回隊伍編號最大值 void insertTeam(Team x){ //功能函數6:將新的Team對象按照編號大小順序加入teams void insertContest(Contest x){ //功能函數7:將新的Contest對象按照編號大小順序加入contests void insertSchool(School x){ //功能函數8:將新的School對象按照編號大小順序加入schools void writeToFile(){ //功能函數9:保存數據進入文檔 void readFromFile(){ //功能函數10:從文檔中讀取 void firstUse(){ //功能函數11:首次使用 void manageSchool(){ //二級界面1:學校信息管理 void manageContest(){ //二級界面2:比賽信息管理 ...【調用關系圖】
注:在各個函數中都可按需調用功能函數,在圖不再列出
【流程圖】
四、物理設計
以下列出一些數據結構與功能函數。
(1)Team類結構
class Team { public:Team(int n, int school) {this->n = n;this->belongToSchool = school;}Team(int n, int school, int contest) {this->n = n;belongToContest = contest;belongToSchool = school;score = 0;}Team(int n, int school, int contest, int score) {this->n = n;belongToContest = contest;belongToSchool = school;this->score = score;}int getScore() { return score; }int getNoble() { return n; }int getSchool() { return belongToSchool; }int getContest() { return belongToContest; }void setScore(int score) {this->score = score;} private:int score;int n;int belongToContest;int belongToSchool; };(2)School類結構?
class School { public:School() {}School(int n, char* name) {this->n = n;this->name = name;team = 0;for (int i = 0; i < 6; i++) teamNum[i] = 0;sumScore = 0;}void addTeam(int num) { //加入隊伍if (team >= 6) {cout << "隊伍數已滿\n";return;}teamNum[team++] = num;}void Sum(); //求和,可返回分數和,并且將結果儲存在sumScore中int getSum() {return sumScore;}int getNoble() { return n; }string getName() { return name; }int getNum() { return team; }int getNum(int i) {if (i < team) return teamNum[i];} private:int n;string name;int team;int teamNum[6];int sumScore; };(3)Contest類結構
class Contest { public:Contest(int n, char* name) {team = 0;this->n = n;this->name = name;finished = false;}void addTeam(int num) {teamNum[team++] = num;}void finish() { finished = true; }bool isFinished() { return finished; }void rank() { //排序sort(teamNum, teamNum + team, cmpByScore);}int getNoble() { return n; }string getName() { return name; }int getNum() { return team; }int getNum(int i) { return teamNum[i]; } private:bool finished;int n;string name;int team;int teamNum[N]; //存放參賽隊伍 };(4)其他數據結構
vector<Team> teams; vector<Contest> contests; vector<School> schools; int A,B,C; //A:學校數量 B:比賽數量 C:隊伍數量(5)文件讀寫
void writeToFile() { //功能函數9:保存數據進入文檔fstream out;out.open("data.txt", ios::out | ios::ate);out << A << ' ' << B << ' ' << C << '\n';for (int i = 0; i < A; i++) {out << schools[i].getNoble() << schools[i].getName() << "\n";}for (int i = 0; i < B; i++) {out << contests[i].getNoble() << " " << (int)contests[i].isFinished() << contests[i].getName() << "\n";}for (int i = 0; i < C; i++) {out << teams[i].getNoble() << " " << teams[i].getSchool() << " " << teams[i].getContest() << " " << teams[i].getScore() << "\n";}out.close(); } void readFromFile() { //功能函數10:從文檔中讀取fstream in;in.open("data.txt", ios::in);in >> A >> B >> C;for (int i = 0; i < A; i++) {int noble;char s[20];in >> noble;in.getline(s, 20, '\n');School x(noble, s);insertSchool(x);}for (int i = 0; i < B; i++) {int noble;char s[20];in >> noble;int finished = 0;in >> finished;in.getline(s, 20, '\n');Contest x(noble, s);if (finished == 1) x.finish();insertContest(x);}for (int i = 0; i < C; i++) {int noble;int belongC;int belongS;int score;in >> noble >> belongS >> belongC >> score;Team x(noble, belongS, belongC, score);insertTeam(x);schools[findSchool(belongS)].addTeam(noble); //調用學校類函數addTeam,將本隊加入學校數據中contests[findContest(belongC)].addTeam(noble); //更新競賽隊伍數據}in.close();cout << "讀取存檔成功!"; }(6)find函數
int findSchool(int noble) { //功能函數1:尋找學校,返回下標vector<School>::iterator i;int location = 0;for (i = schools.begin(); i != schools.end(); i++) {if (i->getNoble() == noble) return location;else if (i->getNoble() > noble) return -1;else location++;}return -1; } int findContest(int noble) { //功能函數2:尋找賽事,返回下標vector<Contest>::iterator i;int location = 0;for (i = contests.begin(); i != contests.end(); i++) {if (i->getNoble() == noble) return location;else if (i->getNoble() > noble) return -1;else location++;}return -1; } int findTeam(int noble) { //功能函數3:找到編號為noble的隊伍在容器中的下標,找不到返回-1vector<Team>::iterator i;int location = 0;for (i = teams.begin(); i != teams.end(); i++) {if (i->getNoble() == noble) return location;else if (i->getNoble() > noble) return -1;else location++;}return -1; }(7)print函數
void printContestList() { //功能函數4:輸出比賽列表if (contests.empty()) cout << "當前賽事列表為空!\n";vector<Contest>::iterator it;for (it = contests.begin(); it != contests.end(); it++) {cout << "編號" << it->getNoble() << " " << it->getName() << "\t已報名隊伍數量:" << it->getNum() << "\t";if (it->isFinished()) cout << "已結束\n";else cout << "尚未結束\n";} } void printSchoolList() { //功能函數12:輸出學校列表cout << "當前已有學校:\n";vector<School>::iterator it;for (it = schools.begin(); it != schools.end(); it++)cout << "編號" << it->getNoble() << " " << it->getName() << "\t隊伍數量:" << it->getNum() << "\n"; } void printTeamList() { //功能函數13:輸出隊伍列表cout << "當前已有隊伍" << teams.size() << "支\n";vector<Team>::iterator it;for (it = teams.begin(); it != teams.end(); it++)cout << "編號" << it->getNoble() << " 隸屬于" << schools[findSchool(it->getSchool())].getName() << "參加了"<<contests[findContest(it->getContest())].getName()<< endl; }(8)insert函數
void insertTeam(Team x) { //功能函數6:將新的Team對象按照編號大小順序加入teamsif (findTeam(x.getNoble()) != -1) {cout << "該編號的隊伍已經存在";return;}else {vector<Team>::iterator i;bool flag = false; //標記是否在中間插入過,如果沒有,說明應該插在尾部for (i = teams.begin(); i != teams.end(); i++) {if (i->getNoble() > x.getNoble()) { //第一個編號比x更大的,插入在此處之前flag = true; //標記更新teams.insert(i, x); //插入break; //找到了即退出} //中間沒有合適位置,直接push_back到尾部}if (!flag) teams.push_back(x);} } void insertContest(Contest x) { //功能函數7:將新的Contest對象按照編號大小順序加入contestsif (findContest(x.getNoble()) != -1) {cout << "該編號的競賽已經存在";return;}else {vector<Contest>::iterator i;bool flag = false; //標記是否在中間插入過,如果沒有,說明應該插在尾部for (i = contests.begin(); i != contests.end(); i++) {if (i->getNoble() > x.getNoble()) { //第一個編號比x更大的,插入在此處之前flag = true; //標記更新contests.insert(i, x); //插入break; //找到了即退出}}if (!flag) contests.push_back(x); //中間沒有合適位置,直接push_back到尾部} } void insertSchool(School x) { //功能函數8:將新的School對象按照編號大小順序加入schoolsif (findSchool(x.getNoble()) != -1) {cout << "該編號的學校已經存在";return;}else {vector<School>::iterator i;bool flag = false; //標記是否在中間插入過,如果沒有,說明應該插在尾部for (i = schools.begin(); i != schools.end(); i++) {if (i->getNoble() > x.getNoble()) { //第一個編號比x更大的,插入在此處之前flag = true; //標記更新schools.insert(i, x); //插入break; //找到了即退出}}if (!flag) schools.push_back(x); //中間沒有合適位置,直接push_back到尾部} }(9)界面函數
void manageSchool() { //二級界面1:學校信息管理char choice;while (true) {cout << "***********學校信息編輯***********\n";cout << "1.輸出全部學校信息\n";cout << "2.新加入學校信息\n";cout << "3.刪除學校\n";cout << "0.返回\n";cin >> choice;if (choice == '1') {if (schools.empty()) cout << "當前學校列表為空!\n";vector<School>::iterator it;for (it = schools.begin(); it != schools.end(); it++)cout << "編號" << it->getNoble() << " " << it->getName() << " 含有隊伍數量:" << it->getNum() << "\n";}else if (choice == '2') {cout << "請輸入學校編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findSchool(noble) != -1) cout << "已有該編號的學校,錄入失敗!\n";else if (noble <= 0)cout << "必須輸入正整數!\n";else {cout << "請輸入學校名稱:";char s[50];cin >> s;School newAdd(noble, s);A++;insertSchool(newAdd);}}else if (choice == '3') {cout << "您要刪除的學校編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findSchool(noble) == -1) cout << "該學校編號不存在,請重新輸入\n";else {School& del = schools[findSchool(noble)];C -= del.getNum();for (int i = 0; i < del.getNum(); i++) {cout << "該學校編號為" << del.getNum(i) << "的隊伍已被刪除\n";teams.erase(teams.begin() + findTeam(del.getNum(i)));}cout << "編號為:" << noble << "的" << schools[findSchool(noble)].getName() << "已被成功刪除!\n";schools.erase(schools.begin() + findSchool(noble));A--;}}else if (choice == '0') { writeToFile(); break; }} } void manageContest() { //二級界面2:比賽信息管理char choice;while (true) {cout << "***********賽事信息編輯***********\n";cout << "1.輸出全部賽事信息\n";cout << "2.新加入賽事\n";cout << "3.隊伍打分\n";cout << "4.查看比賽結果\n";cout << "0.返回\n";cin >> choice;if (choice == '1') {printContestList();}else if (choice == '2') {cout << "請輸入賽事編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findContest(noble) != -1) cout << "已有該編號的比賽,錄入失敗!\n";else if (noble <= 0)cout << "必須輸入正整數!\n";else {cout << "請輸入賽事名稱:";char s[20];cin >> s;Contest newAdd(noble, s);B++;insertContest(newAdd);cout << "加入成功!\n";}}else if (choice == '3') {printContestList();cout << "輸入要進行打分的比賽編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findContest(noble) == -1) cout << "比賽不存在!\n";else {Contest& now = contests[findContest(noble)];if (now.getNum() < 10) {cout << "報名隊伍過少,比賽不能開始\n";continue;}else if (now.isFinished()) {cout << "該比賽已打分\n";continue;}for (int i = 0; i < now.getNum(); i++) {Team& nowTeam = teams[findTeam(now.getNum(i))];cout << "請給" << i + 1 << "號隊伍(編號" << now.getNum(i) << "," << schools[findSchool(nowTeam.getSchool())].getName() << ")打分:";int score;cin >> score;nowTeam.setScore(score);}now.finish();now.rank();}}else if (choice == '4') {printContestList();cout << "要查看那一場比賽結果:";int noble;cin.clear();cin.ignore();cin >> noble;if (findContest(noble) == -1) cout << "比賽不存在!\n";else {Contest& now = contests[findContest(noble)];if (!now.isFinished())cout << "尚未打分,無法查看結果!\n";else {now.rank();for (int i = 0; i < now.getNum(); i++) {Team& nowTeam = teams[findTeam(now.getNum(i))];cout << "No." << i + 1 << " " << schools[findSchool(nowTeam.getSchool())].getName() << " 分數:" << nowTeam.getScore() << "\n";}}}}else if (choice == '0') { writeToFile(); break; }} } void teamRegistration() { //二級界面3:隊伍報名管理char choice;while (true) {cout << "***********隊伍報名管理***********\n";cout << "1.學校批量報名\n";cout << "2.新建一支隊伍\n";cout << "3.查看所有隊伍狀態\n";cout << "0.返回\n";cin >> choice;if (choice == '1') {printSchoolList();cout << "請輸入學校編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findSchool(noble) == -1) cout << "該編號的學校不存在!\n";else {School& nowSchool = schools[findSchool(noble)];int left = 6 - nowSchool.getNum();cout << "要報名的隊伍數(剩余容量" << left << "):";int num;cin >> num;if (num > left) {cout << "名額不足!\n";continue;}else if (num < 0) {cout << "必須輸入正整數\n";continue;}else {printContestList();int i = 0;while (i < num) {cout << "隊伍" << i + 1 << "報名的比賽編號:";int test;cin.clear();cin.sync();cin >> test;if (findContest(test) == -1) {cout << "報名的比賽不存在,請重新輸入\n";continue;}Contest& nowContest = contests[findContest(test)];Team newTeam(MaxOfTeamNoble() + 1, noble, test);C++; i++;cout << "報名成功!\n";if (nowContest.isFinished()) {cout << "當前比賽已開始,請輸入該隊伍成績:";int score;cin.clear();cin.sync();cin >> score;newTeam.setScore(score);nowContest.rank();}insertTeam(newTeam);nowSchool.addTeam(newTeam.getNoble());nowContest.addTeam(newTeam.getNoble());}}}}else if (choice == '2') {printSchoolList();cout << "該隊隸屬學校:";int noble;cin.clear();cin.ignore();cin >> noble;if (findSchool(noble) == -1) cout << "該學校不存在!\n";else {School& nowSchool = schools[findSchool(noble)];int left = 6 - nowSchool.getNum();if (left == 0) {cout << "該學校隊伍已滿\n";continue;}printContestList();cout << "報名的比賽編號:";int test;cin.clear();cin.sync();cin >> test;if (findContest(test) == -1) {cout << "報名的比賽不存在\n";continue;}Contest& nowContest = contests[findContest(test)];Team newTeam(MaxOfTeamNoble() + 1, noble, test);C++;cout << "報名成功!\n";if (nowContest.isFinished()) {cout << "當前比賽已開始,請輸入該隊伍成績:";int score;cin.clear();cin.sync();cin >> score;newTeam.setScore(score);nowContest.rank();}insertTeam(newTeam);nowSchool.addTeam(newTeam.getNoble());nowContest.addTeam(newTeam.getNoble());}}else if (choice == '3') {if (teams.empty())cout << "當前隊伍為空\n";else printTeamList();}else if (choice == '0') {writeToFile();return;}} } void viewPrize() { //二級界面4:查詢學校獲獎信息char choice;while (true) {cout << "*************獲獎查詢*************\n";cout << "1.查詢學校獲獎信息\n";cout << "2.查詢競賽獲獎信息\n";cout << "0.退出\n";cin >> choice;if (choice == '1') {printSchoolList();cout << "請輸入學校編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findSchool(noble) == -1) {cout << "該學校不存在\n";}else {School& nowSchool = schools[findSchool(noble)];bool isFind = false;for (int i = 0; i < nowSchool.getNum(); i++) { //遍歷該學校的每一支隊伍Team& nowTeam = teams[findTeam(nowSchool.getNum(i))];Contest& nowContest = contests[findContest(nowTeam.getContest())];nowContest.rank();if (nowContest.isFinished()) { //查找前三中是否有該隊伍int prize=1;int i;for (i = 0; i < 3; i++) {if(i==0) prize=1;else if(teams[findTeam(nowContest.getNum(i))].getScore()!=teams[findTeam(nowContest.getNum(i-1))].getScore())prize=i+1;//考慮到分數一樣獎牌也應該一樣的情況if (nowContest.getNum(i) == nowTeam.getNoble()) {cout << nowSchool.getName() << "的隊伍在編號為" << nowContest.getNoble() << "的" << nowContest.getName() << "比賽中,獲得了" << prize << "等獎\n";isFind = true;}}//考慮后續還有分數相平的情況while(teams[findTeam(nowContest.getNum(i))].getScore()==teams[findTeam(nowContest.getNum(i-1))].getScore()&&i<nowContest.getNum()){if (nowContest.getNum(i) == nowTeam.getNoble()) {cout << nowSchool.getName() << "的隊伍在編號為" << nowContest.getNoble() << "的" << nowContest.getName() << "比賽中,獲得了" << prize << "等獎\n";isFind = true;}i++;}}}if (!isFind) cout << "無獲獎信息\n";}}else if (choice == '2') {printContestList();cout << "請輸入比賽編號:";int noble;cin.clear();cin.ignore();cin >> noble;if (findContest(noble) == -1) {cout << "該比賽不存在\n";}else {Contest& now = contests[findContest(noble)];now.rank();if (!now.isFinished())cout << "該比賽尚未結束\n";else {int prize=1;int i;for (i = 0; i < 3; i++) {if(i==0) prize=1;else if(teams[findTeam(now.getNum(i))].getScore()!=teams[findTeam(now.getNum(i-1))].getScore())prize=i+1;Team& nowTeam = teams[findTeam(now.getNum(i))];cout << prize << "等獎:" << schools[findSchool(nowTeam.getSchool())].getName() << "的隊伍(編號" << nowTeam.getNoble() << ") 分數為:" << nowTeam.getScore() << endl;}while(teams[findTeam(now.getNum(i))].getScore()==teams[findTeam(now.getNum(i-1))].getScore()&&i<now.getNum()){Team& nowTeam = teams[findTeam(now.getNum(i))];cout << prize << "等獎:" << schools[findSchool(nowTeam.getSchool())].getName() << "的隊伍(編號" << nowTeam.getNoble() << ") 分數為:" << nowTeam.getScore() << endl;i++;}}}}else if (choice == '0') {writeToFile();return;}} } void printScoreRank() { //二級界面5:總分排行榜cout << "************總分排行榜************\n";int m = schools.size();int* rankList = new int[m];for (int i = 0; i < m; i++) {rankList[i] = i;schools[i].Sum();}sort(rankList, rankList + m, cmpBySum);int prize;for (int i = 0; i < m; i++) {if(i==0) prize=1;else if(schools[rankList[i]].getSum()!=schools[rankList[i-1]].getSum())prize=i+1;cout << "No." << prize << "\t" << schools[rankList[i]].getName();//for (int j = 0; j < 20 - (schools[rankList[i]].getName()).length(); j++) cout <<" ";cout << "(" << schools[rankList[i]].getSum() << ")\n";}delete[] rankList; } void printPrizeRank() { //二級界面6:獲獎排行榜cout << "************獎牌排行榜************\n";cout << "名次\t金\t銀\t銅\t編號\t 學校名稱\t\n";int m = schools.size();int* gold = new int[m];int* silver = new int[m];int* bronze = new int[m];for (int i = 0; i < m; i++) gold[i] = silver[i] = bronze[i] = 0;int* rankList = new int[m];for(int i=0;i<B;i++){contests[i].rank();}for(int i=0;i<A;i++){schools[i].Sum();}for (int i = 0; i < m; i++) {School& nowSchool = schools[i];for (int j = 0; j < nowSchool.getNum(); j++) { //遍歷該學校的每一支隊伍Team& nowTeam = teams[findTeam(nowSchool.getNum(j))];Contest& nowContest = contests[findContest(nowTeam.getContest())];if (nowContest.isFinished()) { //查找前三中是否有該隊伍if (nowContest.getNum(0) == nowTeam.getNoble()){gold[i]++;}if (nowContest.getNum(1) == nowTeam.getNoble())silver[i]++;if (nowContest.getNum(2) == nowTeam.getNoble())bronze[i]++;}}rankList[i] = i;}for (int i = 0; i < m - 1; i++)for (int j = i + 1; j < m; j++) {bool swap = false;if (gold[rankList[i]] < gold[rankList[j]])swap = true;else if (gold[rankList[i]] == gold[rankList[j]])if (silver[rankList[i]] < silver[rankList[j]])swap = true;else if (silver[rankList[i]] == silver[rankList[j]])if (bronze[rankList[i]] < bronze[rankList[j]])swap = true;else if(bronze[rankList[i]] == bronze[rankList[j]])if(schools[rankList[i]].getSum()<schools[rankList[j]].getSum())swap=true;if (swap) {int t = rankList[i];rankList[i] = rankList[j];rankList[j] = t;}}for (int i = 0; i < m; i++) {cout << "No." << i + 1 << "\t"<<gold[rankList[i]] << "\t" << silver[rankList[i]] << "\t" << bronze[rankList[i]];cout << "\t" << schools[rankList[i]].getNoble() << "\t" << schools[rankList[i]].getName()<<"\n";}delete[] gold;delete[] silver;delete[] bronze;delete[] rankList; } void printInformation() { //二級界面7:程序信息cout << "************程序版本信息************\n";cout << "此程序為Jayden Wang 獨立自主設計\n";cout << "用作數據結構項目設計\n";cout << "更新日志:\n2022.5.17 程序框架搭建完成\n";cout << "2022.5.19 發布 Vision 1.0.0 Beta.\n";cout << "2022.5.19晚 v1.1.0 \n\t修復了mac端輸出成績表時出現死循環的問題;修復了每讀一次文檔,學校與比賽名稱前多一個空格的問題。\n ";cout << "2022.5.19晚 v1.1.1\n\t修復了模塊5輸出不正確的bug,輸出了模塊6輸出不正確的bug\n";cout << "2022.5.24 v1.1.2\n\t修復了在查詢學校獲獎信息時,因為未調用排序rank()算法而產生的錯誤\n";cout << "2022.5.25 v1.2.1\n\t界面美化、加入了新功能:并列學校相同獎項算法,例如:如果有兩個第一名,則獎項分別為1 1 3等獎,如果第三名與第四名分數相同,則獎項為1 2 3 3,以此類推\n"; } void menu() { //一級界面(主界面)cout << "*********歡迎使用管理系統*********\n";fstream file;file.open("data.txt", ios::in);if (!file.is_open()) {cout << "未找到數據文件,本次為首次使用,請根據提示錄入數據.\n";file.close();firstUse();}else {cout << "已找到存檔\n";file.close();readFromFile();}char choice = ' ';while (choice != 7) {cout << "\n**************操作****************\n";cout << "1.學校信息管理\n";cout << "2.賽事信息管理\n";cout << "3.隊伍報名管理\n";cout << "4.查看獲獎信息\n";cout << "5.總分排行榜\n";cout << "6.獲獎排行榜\n";cout << "7.關于本程序\n";cout << "0.保存并退出\n";cin >> choice;switch (choice) {case '1':manageSchool(); break;case '2':manageContest(); break;case '3':teamRegistration(); break;case '4':viewPrize(); break;case '5':printScoreRank(); break;case '6':printPrizeRank(); break;case '7':printInformation(); break;case '0':writeToFile(); return;default:break;}} }五、測試數據
data.txt儲存示例(數據為隨意編造,與對應大學實際水平無關)
8 4 44 //A,B,C 1 江蘇科技大學 //參賽學校數據 2 蘇州科技大學 3 江蘇大學 4 浙江大學 5 北京大學 6 清華大學 7 中國科學技術大學 8 武漢大學 1 1 C++ //比賽項目數據 2 1 JAVA 3 1 PYTHON 4 0 C# 1 1 1 90 //隊伍數據 2 1 2 99 3 1 3 98 4 1 4 0 5 2 3 95 6 2 1 80 7 3 1 79 8 3 1 69 9 3 1 88 10 3 1 91 11 3 1 92 12 4 1 95 13 4 1 91 14 4 2 98 15 4 2 96 16 4 2 94 17 4 3 92 18 2 1 24 19 2 1 99 20 2 2 92 21 1 2 88 22 1 3 94 23 5 2 89 24 5 3 100 25 5 2 92 26 5 3 92 27 5 2 94 28 5 4 0 29 6 2 99 30 6 3 93 31 7 3 97 32 7 4 0 33 7 4 0 34 7 4 0 35 7 4 0 36 7 3 10 37 8 4 0 38 8 3 99 39 8 4 0 40 8 4 0 41 6 4 0 42 6 4 0 43 6 2 100 44 8 3 8?補充
本程序得益于開始的精心數據結構設計,預留了很多升級空間:比如單個修改刪除隊伍數據、刪除學校包括其下轄隊伍(這個其實已經做了,做完了才發現沒有要求),刪除比賽以及內含隊伍,來達到更逼真地模仿一般的管理系統;本程序的尋址通過find函數實現,插入使用insert函數實現,與單純的數組下標尋址相比,對于編號的連續性其實沒有依賴,也不需要事先規定學校比賽數量
????????——但是筆者是在是太忙碌著對付期末考試(lan)了,所以......這樣也夠用了。
項目2:校園導游咨詢
一、設計主要要求
【問題描述】
設計一個校園導游程序,為來訪的客人提供各種信息查詢服務。
【基本要求】
(1)?設計你所在學校的校園平面圖,所含景點不少于10個.以圖中頂點表示校內各景點,存放景點名稱、代號、簡介?等信息;以邊表示路徑,存放路徑長度等相關信息。
??(2)??為來訪客人提供圖中任意景點相關信息的查詢。
(3)?為來訪客人提供圖中任意景點的問路查詢,即查詢任意兩個景點之間的一條最短的簡單路徑。
【測試數據】
以江蘇科技大學長山校區為例。
【實現提示】
一般情況下,校園的道路是雙向通行的,可設校園平面圖是一個無向網.頂點和邊均含有相關信息.
二、問題分析和任務定義
(1)設計地圖:地圖標點,并編寫景點相關信息,便于旅客查詢。
(2)設計存儲:用無向圖,將景點存放,并設計各個結點之間的拓撲圖。
(3)設計算法:使用Dijkstra算法計算最短路徑。
限制條件:景點數量>=10
三、邏輯設計
【存儲結構】
(1)無向圖存儲路徑信息(拓撲圖見預設數據)
#define M 999 int Map[N][N] = { {M,100,M,200,M,M,M,M,M,M}, {100,M,80,150,M,M,M,M,M,M}, {M,80,M,M,120,110,M,M,M,M}, {200,150,M,M,50,M,M,M,M,M}, {M,M,120,50,M,M,150,230,M}, {M,M,110,M,M,M,80,60,M,M}, {M,M,M,M,M,80,M,M,M,100}, {M,M,M,M,150,60,M,M,90,70}, {M,M,M,M,230,M,M,90,M,50}, {M,M,M,M,M,M,100,70,50,M} };(2)景點類ScenicSpot
ADT ScenicSpot{Data編號景點名稱景點介紹OperationConstructor初始數值:編號、名稱、介紹功能:初始化對象的上述內容print前置條件:無輸入:無功能:表格狀輸出列表編號與名稱輸出:列表編號與名稱后置條件:無printIntroduce前置條件:無輸入:無功能:輸出景點介紹輸出:景點介紹后置條件:無 end ADT(3)景點容器
vector<ScenicSpot> SpotList;
(4)路徑數組
int path[N];
【查詢景點信息模塊】
void query():簡單的詢問信息功能
【查詢景點路徑模塊】
void findPath():詢問功能,返回最短路徑功能,輸出路徑功能
int Dijkstra():Dijkstra最短路算法
【調用關系圖】
【流程圖】
四、物理設計
【景點類】
class ScenicSpot { public:ScenicSpot(int noble, string name, string introduce) { //構造函數this->noble = noble;this->name = name;this->introduce = introduce;}void print() { //用于表格狀輸出列表總體信息cout << noble << "\t" << name << "\n";}void printIntroduce() {//輸出景點介紹cout << introduce << endl;} private:int noble;string name;string introduce; };【查詢景點信息】
void query() {cout << "你要查詢的景點編號(1-10):";int n;cin >> n;if (n < 1 || n>10) {cout << "輸入不合法!\n";return;}SpotList[n - 1].print();SpotList[n - 1].printIntroduce(); }?【查詢景點路徑】?
void findPath() {cout << "你要查詢從哪個景點到哪個景點的最短路徑:";int a, b;cin >> a >> b;if (a >= 1 && a <= 10 && b >= 1 && b <= 10) {cout << "最短路徑長度為" << Dijkstra(a, b) << "\n";stack<int> way;int nowAt = b - 1;while (nowAt != -1) {way.push(nowAt + 1);nowAt = path[nowAt];}cout << "最優路徑為:";while (!way.empty()) {cout << way.top();if (way.top() != b) cout << "->";way.pop();}cout << '\n';}else {cout << "輸入不合法!\n";} }【Dijkstra算法】
int Dijkstra(int A, int B) {int a, b;a = A - 1; b = B - 1;bool visited[N]; //用來記錄int dist[N];for (int i = 0; i < N; i++) {dist[i] = Map[i][a]; //visited[i] = false; //標記為未訪問if (i == a) path[i] = -1;else if (Map[i][a] == M) path[i] = -1;else path[i] = a;}dist[a] = 0; visited[a] = true; path[a] = -1; //初始化int hasVisited = 1;while (hasVisited < N) {int min, minLen = M;for (int i = 0; i < N; i++)if ((!visited[i]) && (dist[i] < minLen)) {min = i; minLen = dist[i];}visited[min] = true;hasVisited++;for (int i = 0; i < N; i++)if (dist[i] > dist[min] + Map[min][i]) {dist[i] = dist[min] + Map[min][i];path[i] = min;}}return dist[b]; }五、預設數據
【景點地圖】
| 1 | 三號組團 |
| 2 | 西苑食堂 |
| 3 | 明德園 |
| 4 | 文體中心 |
| 5 | 西操場 |
| 6 | 文理大樓 |
| 7 | 北苑 |
| 8 | 求索園 |
| 9 | 東苑食堂 |
| 10 | 圖書館 |
【拓撲圖】
注:數據不與現實吻合
項目3:算術表達式求解
一、設計主要要求
【問題描述】
設計一個簡單的算術表達式計算器。
【基本要求】
?實現標準整數類型的四則運算表達式的求值(包含括號,可多層嵌入).
【測試數據】
(30+2*70)/3-12*3
?5+(9*(62-37)+15)*6
?要求自行設計非法表達式,進行程序測試,以保證程序的穩定運行。
【實現提示】
可以設計以下輔助函數
status isNumber(char ReadInChar);??//視ReadInchar?是否是數字而返回?TRUE或?FALSE?。
int TurnToInteger(char IntChar);???//?將字符’0’.’9’ 轉換為整數?9
二、問題分析和任務定義
可以實現合法算式的運算。
考慮優先級問題,()內優先,其次*/,最次+-。
采用符號棧存儲運算符,用數據棧存儲已運算的數據。
可以識別非法算是并給出提示。
注意點:謹慎考慮符號重復出現時的情況、處理結束符號問題、處理第一個元素加入棧時的判斷。
三、邏輯設計
【數據結構】
(1)優先級矩陣
//優先級矩陣 1表示優先級更高,0表示優先級更低,2表示括號相遇,-1表示不合法 //0~5 表示 (+-*/) int priority[6][6] = { {0,0,0,0,0,2}, {0,1,1,0,0,1}, {0,1,1,0,0,1}, {0,1,1,1,1,1}, {0,1,1,1,1,1}, {-1,1,1,1,1,1} };(2)數據棧和符號棧
stack<double> values; //存放運算數 stack<char> operators; //存放運算符【主要功能函數】
int turnToNum(char c):將符號轉變成對應的數字編號,非法符號返回-1
int compare(char a, char b):比較符號a和符號b的優先級
bool isNumber(char c):判斷是否為數字
double result(double a, char c, double b):產生運算結果
【函數調用關系】
【流程圖】
四、物理設計
【核心算法段】
for (int i = 0; i < (int)strlen(expression); i++) {char &c = expression[i]; //c為引用當前字符if (isNumber(c)) { num = num * 10 + c - '0'; }else if (c == ' ') continue;else if (turnToNum(c) != -1) {if (c != '(') {int pre = i - 1;while (expression[pre] == ' ') pre--;if (expression[pre] != ')') {values.push((double)num);if(show)cout << "壓入" << num << "\n";num = 0;}}if (c == '=') break;if (operators.empty()) {if (show) cout << "壓入" << c << "\n";operators.push(c);}else {bool goOn = true; //標記是否要繼續double a, b, r; //a,b分別存放數字棧最上面的兩個數字,c存放運算結果while (!operators.empty() && goOn) {char cTop = operators.top();switch (compare(cTop, c)) {case 1: //棧頂優先級比當前大,消耗棧頂操作符,并計算operators.pop();if (show) cout << "彈出" << cTop << "\n";b = values.top(); values.pop();if (show)cout << "彈出" << b << "\n";a = values.top(); values.pop();if (show)cout << "彈出" << a << "\n";r = result(a, cTop, b);values.push(r);if (show)cout << "壓入" << r << "\n";break;case 0: //棧頂優先級比當前小,將當前符號壓入operators.push(c);if (show)cout << "壓入" << c << "\n";goOn = false;break;case 2: //特殊的,當括號相遇,僅做彈出括號操作if (show)cout << "彈出" << cTop << "\n";operators.pop();goOn = false;break;}}if (operators.empty() && goOn) {operators.push(c);if (show)cout << "壓入" << c << "\n";}}}else {cout << "該算式非法\n";continue;}}while (!operators.empty()) {int a, b, c;char cTop = operators.top();operators.pop();b = values.top(); values.pop();a = values.top(); values.pop();c = result(a, cTop, b);values.push(c);}cout << "Answer is " << values.top() << endl;?補充:這個算法很基礎......也找不到什么特別能體現水平的點......優化了一下報錯機制,處理了一下開頭負數(如-1*3這樣的算式)。如果有兩個符號中間沒有數字的情況,程序會認為中間的數字為0(如1+*2等價為1+0*2答案為1,而非報錯),姑且算是機制而不是bug吧^ ^
補充2:本程序設計了開發者模式(輸入&開啟),打開后將顯示棧中元素每一次的壓入和彈出情況,便于觀察內部運行的邏輯(筆者修改bug時就一直使用的是這個方法)。
開發工具
Windows端(筆者的臺式機):Microsoft Visual Studio 2019
Mac端(筆者的筆記本):Microsoft Visual Studio Code
結語
感謝觀看!
總結
- 上一篇: 360个人图书馆复制不了
- 下一篇: python中字典数据的特点_Pytho