摘 要:计算机程序设计高级语言在处理数据的时候一般要用到循环,强调数据的规律性,文章指出在规律不明显的情况下可以用数组做字典,用查表的方法使用数据,让枚举或者统计程序大大简化。
关键词:枚举;数组;字典
作者简介:佘可,湖北省咸宁高中。(湖北 咸宁 437000)
中图分类号:G633.67 文献标识码:A 文章编号:1671-0568(2019)06-00102-03
现代计算机的主要应用之一是进行数据处理,一般的高级程序设计语言如Pascal,C,C++,VB,Python等都有顺序、选择、循环三种基本程序结构和整数、实数、字符串、数组等基本数据类型。其中,顺序结构让程序按流程自动执行,选择结构主要用于做出判断进行分支,循环结构主要用于按规律自动执行某些操作,而整数、实数等数据类型可以描述基本数据,数组可以进行简易的大数据组织。这些有机结合在一起的就是简单程序设计的基础,可以处理一般的数据计算。当前,程序设计者的主要目的是实现程序的易读性和可扩展性,所以程序中如何找到更普适的规律显得非常重要,数组除了可以方便组织大规模的数据之外,还可以巧妙地进行规则的简化。
比如,一次学生考试中,卷面满分100分,实际得分用ABCDE五个等级表示,卷面得分90分以上(含)换算成A,80分以上(含)换算成B,70分以上(含)换算成C,60分以上(含)换算成D,低于60分的为E,这是一个典型的分支的例子,一般的教材上采用if嵌套或者多分支switch来实现,典型如下:
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';
此程序简单易读,但是要修改和扩展就显得不便,假设分级的分数不是 90,80,等级不是5个而是更多,那么程序的修改会较大,我们尝试使用高级语言里面的数组来找到更好的对应关系。
高级语言一般都有数组这种基本的数据类型,如C++定义数组 int a[10],这样建立了数字a[i]和下标i之间的对应关系,可以通过下标i访问数据a[i],规律不明显甚至没有规律的数据。设置两个数组分别对应分级的分数和等级,从小到大枚举到小于自己分数的最大分级分数,对应的等级就是该得的等级。
#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的分数值
i--; //回退一格
cout< } return 0; } 因此,巧妙利用数组建立一个分数和等级之间的一个对应表,用查表的方法来做数据分析,可以使程序更加简洁,使扩展性大大提高,也不损失效率和可读性。下面再看两个例子:阶梯电费(洛谷P1010),据闽价电[2006]27号规定,月用电量在150千瓦时及以下部分按每千瓦时0.4463元执行,月用电量在151~400千瓦时的部分按每千瓦时0.4663元执行,月用电量在401千瓦时及以上部分按每千瓦时0.5663元执行。请编写一个程序,已知用电总计,根据电价规定,计算出应交的电费应该是多少。 分级电价的起点和电费之间没有什么明显规律,仿照上面的例子,用m数组记录电价分级起点,对应的电费就放在r数组里面,枚举i,直到m[i]>x,然后往下统计电费。 #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; //取代这个数字 for (; i>0; i--) p+=f[i]*(s[i]-s[i-1]); //反向阶梯计价累加 cout< } 进制转换(经典例题),以十进制转换成十六进制为例,一般使用短除法。将x除以16,余数进行处理,商继续除。但是余数小于10的时候对应显示0123456789,余数大于10的时候要用ABCDEF六个字符分别表示10-15,一般的教科书这段是这样写的,用一个判断对余数进行分别处理: while (x>0) { k=x%16;//取得余数 if (k<10)s=char(k+'0')+s; //小于10的余数按数字处理
else s=char(k-10+'A')+s;// >=10的余數按字母处理
x=x/16;
}
利用若用数组建立0-15与字符‘0-‘F的对应关系,先定义const string tzb=”0123456789ABCDEF”,那么数字和字符之间就建立了连续的对应关系,程序长度大大减少:
while (x>0)
{
k=x%16;//取得余数
s=tzb[k]+s; //将余数对应的字符加在s前面
x=x/16;
}
判断今天星期几。有一种判断星期几的思路是:已知公元1900年1月1日星期日,看今天到那天共有多少天,这个日期除以7的余数就是星期几。但是这里有几个需要分支计算的地方,一个是每个月的天数根据月份的不同而不同,输出的0-6也要换算成人们容易接受的Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,这里我们都按上面的做法用数组处理。定义整数数组int month[]={0,31,28,31,30,31,30,31,31,30.31,30,31} 分别表示每个月的天数,这样直接查表就可以省掉很多月份的判断;再定义字符串数组 string s[]={“Sunday”,”Monday”,”Tuesday”,”Wednesday",”Thursday”,”Friday”,”Saturday”},这样得到余数后按下表输出对应的字符串就是相应的星期。
#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列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。现在给出n行m列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。 输入格式: 第一行是用一个空格隔开的两个整数n和m,分别表示雷区的行数和列数。接下来n行,每行m个字符,描述了雷区中的地雷分布情况。字符“*”表示相应格子是地雷格,字符“?”表示相应格子是非地雷格。相邻字符之间无分隔符。 输出格式:输出文件包含nn行,每行mm个字符,描述整个雷区。用“*”表示地雷格,用周围的地雷个数表示非地雷格。相邻字符之间无分隔符。 输入样例1: 3 3 *?? ??? ?*? 输出样例1: *10 221 1*1 输入样例2: 2 3 ?*? *?? 输出样例2: 2*1 *21 每个格子要统计其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子的信息,虽然用坐标可以用-1,0,1两两组合,但是没有明显的规律,要是写8个if判断的话会比较麻烦,可以考虑使用数组来对应这些坐标偏移形成规则。 设置行列偏移数组dr[]={-1,-1,-1,+0,+0,+1,+1,+1}; dc[]={-1,+0,+1,-1,+1,-1,+0,+1};这样当i=0,1,2,3,4,5,6,7的时候,dr和dc的取值就分别是(-1,-1),(-1,0),(-1,1)等8个方向的增量,完成了规则的对应。 #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++)