1 課題描述
給出n個學生的m門考試的成績表,每個學生的信息由學號、姓名以及各科成績組成。對學生的考試成績進行有關統計,並打印統計表。
2 問題分析和任務定義
(1) 按總分數高低次序,打印出名次表,分數相同的為同一名次;
(2) 按名次打印出每個學生的學號、姓名、總分以及各科成績。
(3) 注意測試邊界數據。
(4) 對各科成績設置不同的權值。(附加功能)
3 邏輯設計
1)數據類型:
對於學生所包含的信息,學號使用整數型,姓名使用字符串型,各科成績和總成績還有加權成績使用浮點型。同時設置浮點型數組來存儲各科所占權值的比率,設置整數型數組來存儲每個學生的排名。
struct STU
{
int id;///學號
char name[20];///姓名
float score[20];///成績
float rsum;///加權后的總分
float sum;///不加權的總分
}s[110];
float ratios[30];///權值比率
int rerank[100];///學生排名
2)抽象數據類型
ADT Stu{
數據對象D:D是具有相同特征的數據元素的集合。各數據元素均含有類型相同,可唯一標識數據元素的關鍵字。
數據關系R:數據元素同屬一個集合。
input(int n,int m)
操作結果:輸入n個學生的學號,姓名,m科成績。
quick_sort(int n)
操作結果:對n個學生按加權總分進行快速排序。
ranks(int n,int rerank[])
操作結果:對n個學生進行排名,加權總分相同的,獲得相同的名次。
display(int n,int m,int rerank[])
按照排名打印n個學生的學號、姓名、總分和各科分數。
}ADT Stu
3)模塊功能:
功能上分為輸入、排序、排名、打印這三大模塊。其中排序模塊中需要使用排序算法給學生按照加權成績排名。排名模塊需要編寫算法實現相同分數排名相同的要求。
4 詳細設計
學生信息結構體:
struct STU
{
int id;///學號
char name[20];///姓名
float score[20];///成績
float rsum;///加權后的總分
float sum;///不加權的總分
}s[110];
<1>輸入函數: void input(int n,int m)
輸入n個學生的學號,姓名,m科成績。
<2>快速排序函數:void quick_sort(int n)
對n個學生按加權總分進行快速排序。
<3>相同名次處理:void ranks(int n,int rerank[])
對n個學生進行排名,加權總分相同的,獲得相同的名次。
<4>打印函數void display(int n,int m,int rerank[])
按照排名打印n個學生的學號、姓名、總分和各科分數。
5程序編碼
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct STU { int id;///學號 char name[20];///姓名 float score[20];///成績 float rsum;///加權后的總分 float sum;///不加權的總分 }s[110]; int my_cmp(STU a,STU b) { if(a.rsum>=b.rsum)///按照加權后的總分來排序 { return 1; } else { return 0; } } void input(int n,int m) { int i,j; printf("請輸入學生的學號、姓名和各科成績\n"); for(i=0; i<n; i++) { scanf("%d",&s[i].id); scanf(" %s",&s[i].name); for(j=0; j<m; j++) { scanf("%f",&s[i].score[j]); } } } void quick_sort(int n) { sort(s,s+n,my_cmp);///STL庫中的快速排序算法 } void ranks(int n,int rerank[]) { int i,k; k=0; for(i=0;i<n;i++) { if(s[i].rsum==s[i-1].rsum) { rerank[i]=k; } else { k++; rerank[i]=k; } } } void display(int n,int m,int rerank[]) { int i,j; printf("依次打印排名、學號、姓名、總分、加權總分和各科分數\n"); for(i=0; i<n; i++) { printf("%d ",rerank[i]); printf("%d ",s[i].id); printf("%s ",s[i].name); printf("%.2f ",s[i].sum); printf("%.2f ",s[i].rsum); for(j=0; j<m; j++) { printf("%.2f ",s[i].score[j]); } printf("\n"); } } int main() { int n,m,i,j; float ratios[30]; int rerank[100]; printf("請輸入學生人數n:\n"); scanf("%d",&n); printf("請輸入考試科目數m:\n"); scanf("%d",&m); printf("請依次輸入各科的權重\n"); for(i=0; i<m; i++) { scanf("%f",&ratios[i]); } input(n,m); for(i=0; i<n; i++)///計算加權的總分和非加權的總分 { for(j=0; j<m; j++) { s[i].rsum+=s[i].score[j]*ratios[j]; s[i].sum+=s[i].score[j]; } } quick_sort(n); ranks(n,rerank); display(n,m,rerank); return 0; }
6 程序調試與測試
7 結果分析
該程序中學號定義為整型,姓名定義為字符串型,成績定義為單浮點型並保留兩位有效數字。錯誤輸入會造成亂碼和死循環的產生。該程序主要是基於結構體數組來實現排序和輸出的,因而屬於順序表,遍歷輸出的時間復雜度是O(n),空間復雜度也是O(n)。排序所使用的快速排序時間復雜度是O(nlogn)~O(n^2),空間復雜度是O(logn)~O(n)。
8 總結
該程序能夠實現按總分數高低次序打印出名次表(分數相同的為同一名次),按名次打印出每個學生的學號、姓名、總分以及各科成績,同時還實現了給各科加權獲得加權總分的附加功能。基本達到預期目標,但也存在着一些問題,因為使用的是順序表類型的存儲結構實現了隨機存取,但在擴充空間上有着缺陷。該程序雖然簡單,但卻要從實際出發設計,設計的程序要貼近生活,比如在學校中出現成績相同的學生必然有相同的名次,我們平時看到的成績最多是小數點后兩位等一系列問題,告訴我們寫程序要貼近生活,從實際出發。