摘 要:計算機程序設(shè)計高級語言在處理數(shù)據(jù)的時候一般要用到循環(huán),強調(diào)數(shù)據(jù)的規(guī)律性,文章指出在規(guī)律不明顯的情況下可以用數(shù)組做字典,用查表的方法使用數(shù)據(jù),讓枚舉或者統(tǒng)計程序大大簡化。
關(guān)鍵詞:枚舉;數(shù)組;字典
作者簡介:佘可,湖北省咸寧高中。(湖北 咸寧 437000)
中圖分類號:G633.67 文獻標識碼:A 文章編號:1671-0568(2019)06-00102-03
現(xiàn)代計算機的主要應(yīng)用之一是進行數(shù)據(jù)處理,一般的高級程序設(shè)計語言如Pascal,C,C++,VB,Python等都有順序、選擇、循環(huán)三種基本程序結(jié)構(gòu)和整數(shù)、實數(shù)、字符串、數(shù)組等基本數(shù)據(jù)類型。其中,順序結(jié)構(gòu)讓程序按流程自動執(zhí)行,選擇結(jié)構(gòu)主要用于做出判斷進行分支,循環(huán)結(jié)構(gòu)主要用于按規(guī)律自動執(zhí)行某些操作,而整數(shù)、實數(shù)等數(shù)據(jù)類型可以描述基本數(shù)據(jù),數(shù)組可以進行簡易的大數(shù)據(jù)組織。這些有機結(jié)合在一起的就是簡單程序設(shè)計的基礎(chǔ),可以處理一般的數(shù)據(jù)計算。當(dāng)前,程序設(shè)計者的主要目的是實現(xiàn)程序的易讀性和可擴展性,所以程序中如何找到更普適的規(guī)律顯得非常重要,數(shù)組除了可以方便組織大規(guī)模的數(shù)據(jù)之外,還可以巧妙地進行規(guī)則的簡化。
比如,一次學(xué)生考試中,卷面滿分100分,實際得分用ABCDE五個等級表示,卷面得分90分以上(含)換算成A,80分以上(含)換算成B,70分以上(含)換算成C,60分以上(含)換算成D,低于60分的為E,這是一個典型的分支的例子,一般的教材上采用if嵌套或者多分支switch來實現(xiàn),典型如下:
cin>>x;
if (x>=90) cout<<'A';
else if (x>=80) cout<<'B';
else if (x>=70) cout<<'C';
else if (x>=60) cout<<'D';
else cout<<'E';
此程序簡單易讀,但是要修改和擴展就顯得不便,假設(shè)分級的分數(shù)不是 90,80,等級不是5個而是更多,那么程序的修改會較大,我們嘗試使用高級語言里面的數(shù)組來找到更好的對應(yīng)關(guān)系。
高級語言一般都有數(shù)組這種基本的數(shù)據(jù)類型,如C++定義數(shù)組 int a[10],這樣建立了數(shù)字a[i]和下標i之間的對應(yīng)關(guān)系,可以通過下標i訪問數(shù)據(jù)a[i],規(guī)律不明顯甚至沒有規(guī)律的數(shù)據(jù)。設(shè)置兩個數(shù)組分別對應(yīng)分級的分數(shù)和等級,從小到大枚舉到小于自己分數(shù)的最大分級分數(shù),對應(yīng)的等級就是該得的等級。
#include
using namespace std;
const int s[6]= {0,60,79,80,90,9999};
const char g[6]= {'E','D','C','B','A','O'};
//基本等價 cosnt string s="EDCBA";
int i,x;
int main()
{
cin>>x;
{
for (i=0; (s[i]<=x); i++); //找到第一個大于x的分數(shù)值
i--; //回退一格
cout< } return 0; } 因此,巧妙利用數(shù)組建立一個分數(shù)和等級之間的一個對應(yīng)表,用查表的方法來做數(shù)據(jù)分析,可以使程序更加簡潔,使擴展性大大提高,也不損失效率和可讀性。下面再看兩個例子:階梯電費(洛谷P1010),據(jù)閩價電[2006]27號規(guī)定,月用電量在150千瓦時及以下部分按每千瓦時0.4463元執(zhí)行,月用電量在151~400千瓦時的部分按每千瓦時0.4663元執(zhí)行,月用電量在401千瓦時及以上部分按每千瓦時0.5663元執(zhí)行。請編寫一個程序,已知用電總計,根據(jù)電價規(guī)定,計算出應(yīng)交的電費應(yīng)該是多少。 分級電價的起點和電費之間沒有什么明顯規(guī)律,仿照上面的例子,用m數(shù)組記錄電價分級起點,對應(yīng)的電費就放在r數(shù)組里面,枚舉i,直到m[i]>x,然后往下統(tǒng)計電費。 #include using namespace std; int s[] = {0,150, 400, 9999}; double f[] = {0,0.4463, 0.4663, 0.5663}; int x,i; float p; int main() { cin>>x;p=0; for(i = 0; s[i] < x; i++) ; //找到最大的小于x的階梯位置 s[i]=x; //取代這個數(shù)字 for (; i>0; i--) p+=f[i]*(s[i]-s[i-1]); //反向階梯計價累加 cout< } 進制轉(zhuǎn)換(經(jīng)典例題),以十進制轉(zhuǎn)換成十六進制為例,一般使用短除法。將x除以16,余數(shù)進行處理,商繼續(xù)除。但是余數(shù)小于10的時候?qū)?yīng)顯示0123456789,余數(shù)大于10的時候要用ABCDEF六個字符分別表示10-15,一般的教科書這段是這樣寫的,用一個判斷對余數(shù)進行分別處理: while (x>0) { k=x%16;//取得余數(shù) if (k<10)s=char(k+'0')+s; //小于10的余數(shù)按數(shù)字處理
else s=char(k-10+'A')+s;// >=10的余數(shù)按字母處理
x=x/16;
}
利用若用數(shù)組建立0-15與字符‘0-‘F的對應(yīng)關(guān)系,先定義const string tzb=”0123456789ABCDEF”,那么數(shù)字和字符之間就建立了連續(xù)的對應(yīng)關(guān)系,程序長度大大減少:
while (x>0)
{
k=x%16;//取得余數(shù)
s=tzb[k]+s; //將余數(shù)對應(yīng)的字符加在s前面
x=x/16;
}
判斷今天星期幾。有一種判斷星期幾的思路是:已知公元1900年1月1日星期日,看今天到那天共有多少天,這個日期除以7的余數(shù)就是星期幾。但是這里有幾個需要分支計算的地方,一個是每個月的天數(shù)根據(jù)月份的不同而不同,輸出的0-6也要換算成人們?nèi)菀捉邮艿腟unday,Monday,Tuesday,Wednesday,Thursday,F(xiàn)riday,Saturday,這里我們都按上面的做法用數(shù)組處理。定義整數(shù)數(shù)組int month[]={0,31,28,31,30,31,30,31,31,30.31,30,31} 分別表示每個月的天數(shù),這樣直接查表就可以省掉很多月份的判斷;再定義字符串?dāng)?shù)組 string s[]={“Sunday”,”Monday”,”Tuesday”,”Wednesday",”Thursday”,”Friday”,”Saturday”},這樣得到余數(shù)后按下表輸出對應(yīng)的字符串就是相應(yīng)的星期。
#include
using namespace std;
int y,m,d,i;
int month[]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
string ss[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
long long s;
bool islip(int x)
{
bool b1=(x%400==0);
bool b2=(x%4==0)&&(x%100!=0);
return b1||b2;
}
int main()
{
cin>>y>>m>>d;s=0;
for (i=1900;i<=y-1;i++)
if (islip(i)) s+=366;else s+=365;
if (islip(y)) month[2]++;
for (i=1;i<=m-1;i++) s+=month[i];
s+=d;
s%=7;
cout< return 0; } 掃雷游戲(NOIP2015普及組真題)。在n行m列的雷區(qū)中有一些格子含有地雷(稱之為地雷格),其他格子不含地雷(稱之為非地雷格)。玩家翻開一個非地雷格時,該格將會出現(xiàn)一個數(shù)字——提示周圍格子中有多少個是地雷格。游戲的目標是在不翻出任何地雷格的條件下,找出所有的非地雷格?,F(xiàn)在給出n行m列的雷區(qū)中的地雷分布,要求計算出每個非地雷格周圍的地雷格數(shù)。注:一個格子的周圍格子包括其上、下、左、右、左上、右上、左下、右下八個方向上與之直接相鄰的格子。 輸入格式: 第一行是用一個空格隔開的兩個整數(shù)n和m,分別表示雷區(qū)的行數(shù)和列數(shù)。接下來n行,每行m個字符,描述了雷區(qū)中的地雷分布情況。字符“*”表示相應(yīng)格子是地雷格,字符“?”表示相應(yīng)格子是非地雷格。相鄰字符之間無分隔符。 輸出格式:輸出文件包含nn行,每行mm個字符,描述整個雷區(qū)。用“*”表示地雷格,用周圍的地雷個數(shù)表示非地雷格。相鄰字符之間無分隔符。 輸入樣例1: 3 3 *?? ??? ?*? 輸出樣例1: *10 221 1*1 輸入樣例2: 2 3 ?*? *?? 輸出樣例2: 2*1 *21 每個格子要統(tǒng)計其上、下、左、右、左上、右上、左下、右下八個方向上與之直接相鄰的格子的信息,雖然用坐標可以用-1,0,1兩兩組合,但是沒有明顯的規(guī)律,要是寫8個if判斷的話會比較麻煩,可以考慮使用數(shù)組來對應(yīng)這些坐標偏移形成規(guī)則。 設(shè)置行列偏移數(shù)組dr[]={-1,-1,-1,+0,+0,+1,+1,+1}; dc[]={-1,+0,+1,-1,+1,-1,+0,+1};這樣當(dāng)i=0,1,2,3,4,5,6,7的時候,dr和dc的取值就分別是(-1,-1),(-1,0),(-1,1)等8個方向的增量,完成了規(guī)則的對應(yīng)。 #include using namespace std; const int mm=110; int m,n; char a[mm][mm]; int r,c,s; int dr[]={-1,-1,-1,+0,+0,+1,+1,+1}; //8個方向的行r增量 int dc[]={-1,+0,+1,-1,+1,-1,+0,+1}; //8個方向的列c增量 int tr,tc,i; int main() { cin>>m>>n; for (r=1; r<=m; r++) for (c=1; c<=n; c++) cin>>a[r][c]; //度的原始棋盤 for (r=1; r<=m; r++) { for (c=1; c<=n; c++)