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