620 likes | 791 Views
第 3 章 数组. 。。。。。。 3.5 导出数据类型和数组. 3.5 导出类型和数组. 3.5.1 导出类型概念 3.5.2 一维数组与实例 3.5.3 多维数组与实例 3.5.4 数组与字符串. 3.5.1 导出类型概念. 在计算机所处理的数据中,最常见的,也是最需要由计算机高速处理的数据是成批出现的同一类型的数据, C++ 语言中把这类数据称为数组。 导出数据类型,其特点是这种类型的定义是在其它已定义类型的基础上定义的,而且其运算也是确定的。 第四种结构类型. 3.5.2 一维数组与实例.
E N D
第 3章 数组 。。。。。。 3.5 导出数据类型和数组
3.5 导出类型和数组 3.5.1 导出类型概念 3.5.2 一维数组与实例 3.5.3 多维数组与实例 3.5.4 数组与字符串
3.5.1 导出类型概念 在计算机所处理的数据中,最常见的,也是最需要由计算机高速处理的数据是成批出现的同一类型的数据,C++语言中把这类数据称为数组。 导出数据类型,其特点是这种类型的定义是在其它已定义类型的基础上定义的,而且其运算也是确定的。 第四种结构类型
3.5.2 一维数组与实例 数组是同类型元素(分量)的有序组合体。元素的类型可以是C++语言中允许使用的任何一种数据类型(包括任何用户自定义类型)。 数组中的每个元素都有与其对应的下标以标明该元素在数组中的位置。对数组元素的访问通常借助于下标来进行,元素也被称为下标变量。每个数组元素(即下标变量)都可以当作单个变量来使用。 具有一个下标的数组叫做一维数组,它是由n个同一类型数据组成的一维序列。按如下格式来说明一维数组。
1 说明一维数组 <类型名> <数组名> [ <元素数> ] = { <初值表> } 其中的“<类型名>”用于指出数组元素的类型,也称为数组类型。“<数组名>”是一个标识符,是为数组起的名字,该名字还代表数组首元素的地址(指针概念,在以后介绍)。方括号中的“<元素数>”用于指定数组的大小,它必须是一个整数或一个整型的常量表达式。“= { <初值表> }”部分可有可无,若有的话,用于为数组元素置初值;其中的“<初值表>”由一批以逗号分割的常量值所构成。
例如:int a[10]; 说明了一个一维数组,数组名为a,具有10个元素,元素类型为int。要访问a数组的各元素(分量),可通过使用下标变量a[0],a[1],a[2],...,a[9]来实现(注意,规定下标总从0开始)。每一个下标变量a[i]的作用与一个int型简单变量所能起的作用相同。既是说,对int型简单变量可施加的运算与操作同样可施加到int型数组元素(分量)上。除整数外,下标处还可以使用一个整型表达式,表达式的值正是要指定的下标。如,a[2*4+1],a[i+1],a[a[1]-3]都是合法的下标变量。
对a数组元素(下标变量)进行使用: int a[10],i=1; a[3]=123; cin>>a[9]; a[i-1]=a[3]+2*a[2*4+1]; cout<<"a[0]="<<a[0]<<endl; if (a[3]>a[9]) cout<<"a[3]>a[9]"<<endl;
说明了一个int型的一维数组a;向数组元素(下标变量)a[3]赋值;通过cin输入下标变量a[9]的值;使用下标变量a[3]、a[9]参加运算,将运算结果赋值给a[i-1]即a[0],其中的a[i-1]及a[2*4+1]的下标都使用了整型表达式;向cout输出下标变量a[0]的值;使用“if (a[3]>a[9])”进行下标变量的比较运算等。
又如: char arr1[20], arr2[80]; float fa1[15], fa2[6]={1.2,35.6,-22,0.1,66,30}; 说明了两个char型一维数组arr1与arr2,大小分别为20和80;又说明两个float型一维数组fa1与fa2,大小分别为15和6,且为fa2数组赋了初值。
2 一维数组应用实例 1 反序输出问题 2 使用Eratosthenes 筛法求1000以内的素数 3 统计学生成绩
1 反序输出问题 1. 从键盘输入10个int型数,而后按输入的相反顺序输出它们。 实现方式:使用int型数组存放数据,通过下标变化来处理这些数据 。 例如,程序执行后的输入输出界面可设计为: Input 10 integers: 1 2 3 4 5 6 7 8 9 10 ---- The result ---- 10 9 8 7 6 5 4 3 2 1
程序编制: #include <iostream.h> void main(){ int a[10],i; //说明int型一维数组a cout<<"Input 10 integers:"<<endl; //输入10个整数,依次放入各下标变量中 for (i=0; i<10; i++) //下标i从0起,递增变化到9 cin>>a[i]; cout<<"---- The result ----"<<endl; //按反序输出a数组中的各元素 for (i=9; i>=0; i--) //下标i从9起,递减变化到0 cout<<a[i]<<" "; cout<<endl; }
2 使用Eratosthenes 筛法求1000 以内的素数 先将1~1000放在一个数组sieve(看成是一个筛子)中;首先“留下”2(第一个素数),而后把2的倍数统统从数组sieve(筛子)中删去;再“留下”3(第二个素数),而后把3的倍数统统从数组sieve中删去; 再往下是5,7,...。好象是一个筛子,把不需要的数逐步筛去,留下的正是所需要的各素数。 所谓将某数从数组sieve(筛子)中删去,本程序实现时,是将数组中的该数“改写”为0。
程序执行后的输出结果样式如下 (每输出15个素数换一行): 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 … 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997
具体程序: #include<iomanip.h> void main() { const int n=1000; int sieve[n+1]; //筛子sieve for (int j=1; j<n+1; j++) sieve[j]=j; //放入数据 int i=1, count=0;
while(i<n) { i++; if ( sieve[i]!=0 ) { //尚在筛中 cout<<setw(5)<<sieve[i]; count++; if(count%15==0) cout<<endl; //每行15数 for(int k=i; k<n+1; k+=i) //消去倍数 sieve[k]=0; } //if } // while cout<<endl; } //main
进一步改进,使用bool数组 #include<iomanip.h> void main() { const int n=1000; bool sieve[n+1]; //筛子sieve for (int j=1; j<n+1; j++) sieve[j]=true; //放入数据 //sieve[j]为true意味着j在筛中 int i=1, count=0;
while(i<n) { i++; if ( sieve[i] ) { //i尚在筛中 cout<<setw(5)<<i; count++; if(count%15==0) cout<<endl;//每行15数 for(int k=i; k<n+1; k+=i) //消去倍数 sieve[k]=false; } //if } //while cout<<endl; } //main
3 统计学生成绩 输入n个学生的注册号和成绩,计算出平均成绩,并列出成绩最好的前t名学生的注册号和成绩。
程序执行后的输出结果式样如下(n=6,t=3时): Input 6 student's Reg_Num & Score: 1001 88.5 1002 91 1003 85.5 1004 93.5 1005 85 1006 96 Average score:89.9 register-number score 1 1006 96.0 2 1004 93.5 3 1002 91.0
程序如下: #include <iostream.h> void main(){ const int n=6; //共有n个学生 const int t=3; //欲找出前t名最好成绩者 int index[n]; //数组index,存放n个学生的注册号 float score[n]; //数组score,存放n个学生的成绩 cout<<"Input "<<n<<" student's Reg_Num & Score:"<<endl; for (int i=0; i<n; i++) //输入n个学生的注册号及成绩 cin>>index[i]>>score[i];
float sum=0; //放累加和的sum先置为0 for (i=0; i<n; i++) sum += score[i]; //将n个学生的成绩累加到sum上 cout.setf(ios::fixed); //设置以定点数格式输出数据 cout.precision(1); //点后保留1位 cout<<“Average score:”<<sum/n<<endl; //输出平均成绩 cout.width(25); cout<<"register-number score"; //输出“题头行”
/* 通过“for(i=0; i<t; i++){…}”形式的循环,找出前t名最好成绩者,并输出其注册号及成绩。 i=0的循环先使score[0]及index[0]处被交换成为第一名最好成绩者的成绩及注册号,而后输出;i=1的循环先使score[1]及index[1]处被交换成为第二名最好成绩者的成绩及注册号,而后输出;...,如此做法,直到找出前t名最好成绩者,并输出它们的相关信息。 第i次的循环首先找出从score[i]到数组末score[n-1]中的最大者s,并记录其下标值到j1,而后将最大者score[j1]掉换到score[i]的位置上,当然还要将index[j1]掉换到index[i]的位置处,以使index[i]总与score[i]保持一一对应关系。 */
for(i=0; i<t; i++) { //找出前t名最好者 float s = score[i]; //从i分量始score中的最大者s int j1 = i; //j1中记录上述最大者的下标i for(int j=i+1; j<n; j++) //看还有否比s 更大的 if(s<score[j]) { //有更大的时 s=score[j]; //更大者放s j1=j; //对应下标放j1 } //for j 循环体结束
if (j1>i) { //若score[i]到score[n-1]中的最大者 //并非score[i]时,要进行交换 score[j1] = score[i]; score[i] =s ; //使score[i]交换为最大 int tmp = index[j1]; //交换注册号 index[j1] = index[i]; index[i] = tmp; }
cout.width(4); cout<<endl<<i+1; //输出名次号(前t名的第i+1名) cout.width(11); cout<<index[i]; //输出第i+1名学生的注册号 cout.width(12); cout.precision(1); //点后保留1位 cout<<score[i]; //输出第i+1名学生的成绩 } //for i 循环体结束 cout<<endl; }//main结束
3.5.3 多维数组与实例 具有两个下标的数组叫做二维数组。二维数组经常用来表示按行和列格式来存放信息的数据表。要区分表中某个特定的元素,必须指定两个下标。第一个下标表示该元素所在的行,而第二个下标则表示该元素所在的列。 按如下格式来说明二维数组: <类型名> <数组名> [ <行数> ] [ <列数> ] 其中的“<类型名>”及“<数组名>”的含义与一维数组相同。方括号中的“<行数>”与“<列数>”用于指定数组的大小, 它们必须是整数或整型的常量表达式。类似可以说明三维、四维等二维以上的多维数组。
例如:int a[3][4]; 说明了一个二维数组,数组名为a,具有12个元素(3行4列),元素类型为int。要访问a数组的各元素(分量),可通过使用下述12个下标变量: a[0][0],a[0][1],a[0][2],a[0][3],a[1][0],a[1][1],a[1][2],a[1][3],a[2][0],a[2][1],a[2][2],a[2][3]。可以看出,与一维数组一样,二维数组的两个下标(行下标与列下标)也都是从0开始的。 每一个下标变量a[i][j]的作用与一个int型简单变量所能起的作用相同。既是说,对int型简单变量可施加的运算与操作同样可施加到int型数组元素即下标变量a[i][j]上。
例如:int a[3][4]; 另外,还可将上述3行4列的二维数组a看成是具有3个一维数组元素(每个元素为一行,具有4个int型数据)的数组, 可使用a[0]、a[1]、a[2]来表示这3个一维数组。注意,a[0]、a[1]、a[2]的“级别”与上述12个下标变量a[i][j]的“级别”完全不同。a[0]、a[1]、a[2]的“级别”为具有4个int型元素的一维数组(与一维数组说明处的“<数组名>”一样,它们代表3个不同的地址即指针,其中a[0]代表二维数组a的第一行元素的首地址,a[1]、a[2]代表第二与第三行元素的首地址),而下标变量a[i][j]的“级别”为int,它代表一个整数。
如下的程序片段中对所说明的a数组的 元素(下标变量)进行了使用: int a[3][4], i=1, j=1; a[0][0]=123; cin>>a[0][1]; a[2][3]=a[i-1][j-1]+2*a[i-1][j]; cout<<"a[2][3]="<<a[2][3]<<endl; if ( a[0][0]>a[0][1] ) cout<<"a[0][0]>a[0][1]"<<endl;
说明了一个int型的二维数组a;向数组元素(下标变量)a[0][0]赋了值; 通过cin输入下标变量a[0][1]的值;使用下标变量a[i-1][j-1]及a[i-1][j]参加运算,并将运算结果赋值给a[2][3](下标可以是整型表达式);输出下标变量a[2][3]的值;下标变量还可进行比较运算。
又如: float fa1[10][10], fa2[2][3]={ {1.1, 2.2, -3.3 }, { 4.4, -5.5, 6.6 } }; 说明了两个float型二维数组fa1(10行10列)与fa2(2行3列),且为fa2数组赋了初值(使用给两个一维数组赋初值的形式)。也可使用如下的另一种格式为fa2数组赋初值 “float fa2[2][3] = {1.1,2.2,-3.3,4.4,-5.5,6.6};”。
char arr1[3][20]={"12345", "C++ OK!", "I can do it!"}, arr2[10][80]; 说明了两个char型二维数组arr1(3行20列)与arr2(10行80列),并给arr1数组赋了初值,从而使得arr1[0]、arr1[1]、arr1[2]都成为具有了初值的字符串(注意字符串赋初值的方法)。 for(int i=0; i<3; i++) cout<<arr1[i]<<endl; //一次输出“一串”
上述for语句的执行将输出如下三行结果: 12345 C++ OK! I can do it! 同理,具有三个下标的数组叫做三维数组,具有n个下标的数组叫做n维数组。通常,将二维以上的数组统称为多维数组。实际上,多维数组中最常用的只是二维数组。
多维数组应用实例 1 二维数组简单应用 2 二维字符数组 3 画一个四叶玫瑰线图形
1 二维数组简单应用 设有4行4列的数组a,其元素a[i][j]=i+j。 编程序,实现: 1. 求第二行4元素之和; 2. 求第三列4元素之平均值; 3. 求最大数,最小数及主对角线4元素的平方和。
使程序执行后的输出结果为: 0 1 2 3 1 2 3 4 2 3 4 5 3 4 5 6 ------ The result ------ sum_lin2=10 ave_col3=3.5 max_elem=6 min_elem=0 sum_diag=56
#include <iostream.h> void main(){ int a[4][4], i, j; for (i=0; i<4; i++){ //为a数组赋值,并显示在屏幕上 for (j=0; j<4; j++) { a[i][j]=i+j; cout<<" "<<a[i][j]; } cout<<endl; //每4数占一行 } cout<<"------ The result ------"<<endl;
//1. 求第二行4元素之和 //( 第二行元素为a[1][j] (j=0,1,2,3) ) int sum_lin2=0; for (j=0; j<4; j++) sum_lin2+=a[1][j]; cout<<"sum_lin2="<<sum_lin2<<endl; //2. 求第三列4元素之平均值 //(第三列元素为a[i][2] (i=0,1,2,3)) int sum_col3=0; for (i=0; i<4; i++) sum_col3+=a[i][2]; cout<<"ave_col3="<<sum_col3/4.0<<endl;
//3. 求最大数, 最小数及主对角线4元素的平方和 int max_elem=a[0][0], min_elem=a[0][0], sum_diag=0; //先认为a[0][0]为最大数max_elem、又为最小数min_elem for (i=0; i<4; i++) for (j=0; j<4; j++) { if ( a[i][j]>max_elem ) max_elem=a[i][j]; if ( a[i][j]<min_elem ) min_elem=a[i][j]; if ( i==j ) sum_diag+=a[i][j]*a[i][j]; //行列下标相等时,a[i][j]为主对角线元素 } cout<<"max_elem="<<max_elem<<endl; cout<<"min_elem="<<min_elem<<endl; cout<<"sum_diag="<<sum_diag<<endl; }
2 二维字符数组 寻找若干行(字符串)中的最长行并进行某些统计:从键盘输入n个字符串(每串为一行,不超过80个字符,且输入时以回车结束每一行)先存放在一个二维字符数组中。而后统计出每一行中大写字母的出现次数,并找出这些行中的最长行。
程序执行后,屏幕显示结果可为: ----------- Input 4 strings ------------ Hello! ABCabc. 12345 67890 OK! OK! ookk! +*-/% abcde We are students. NK2004. ------ The result ------ count[0] = 4 count[1] = 4 count[2] = 0 count[3] = 3 maxLenLine : 12345 67890 OK! OK! ookk!
数据部分概要: const int n=4; //定义常量n,共输入并处理n行字符 char str[n][81]; //str为char型二维数组,用于盛放输入的n行字符 //(每行最多放80字符另加一结束符) int count[n]; //使用count数组元素记录各行大写字母的出现次数 //对应关系为:count[i]记录第i行中的大写字母个数 char maxLenLine[81]={'\0'}; //盛放最长行,初始化为“空”
处理部分概述: ① 输入n行字符(每行以回车为结束),依次放于一维字符数组str[i]中(注意,str[i]为二维字符数组str的一行),并将记录每行大写字母出现次数的count[i]均置为0(作累加单元用)。 ② 编制循环,依次处理已放在str[0]、str[1]、 ...、str[n-1]中的那n行字符 -- 某行长度超过当前maxLenLine之长度时更换maxLenLine,并从头到尾寻找各行的大写字母且将累加次数放于count[i]之中。 ③ 输出统计出的各行大写字母个数,并输出最长行。
#include <iomanip.h> //use “setw” #include <stdio.h> //use “gets” #include <string.h> //use “strlen” void main() { const int n=4; //共输入并处理n行 char str[n][81], ch; //str数组,盛放n行字符 char maxLenLine[81]={'\0'}; //盛放最长行,初始化为“空” int count[n], i, j; //count[i]记录第i行的大写字母个数 for ( i=0; i<n; i++) count[i]=0; //将count初始化(累加次数用) cout<<"----------- Input "<<n<<" strings ------------"<<endl; for(i=0; i<n; i++) //共输入n行 gets(str[i]); //放于一维数组str[i]中
for(i=0; i<n; i++) { //共处理n行字符 if ( strlen(str[i]) > strlen(maxLenLine) ) strcpy(maxLenLine, str[i]); //更新最长行 for (j=0; j<81 && str[i][j]!='\0'; j++) { //从头到尾处理一遍str[i]数组中的各字符 ch=str[i][j]; if ( ch>='A' && ch<='Z') //若ch为大写字母 count[i]++; //次数加1 } //for j } //for i cout<<"------ The result ------"<<endl; for(i=0; i<n; i++) //输出每行大写字母个数 cout<<setw(10)<<"count["<<i<<"] ="<<setw(2)<<count[i]<<endl; cout<<"maxLenLine : "<<endl; cout<<maxLenLine<<endl; //输出最长行 }
3 画一个四叶玫瑰线图形 实现概述: 1. 四叶玫瑰线图形的极坐标方程为: p = a*sin(2*angle) 其中,angle为极角,变化范围从0度到360度; a为常数,表示所画四叶玫瑰线图形中,矩极点的最长距离; p为极径,与变化范围内的极角angle有上述极坐标方程的关系。
2. 在“文本模式”的“字符屏幕”上“画图”的通常实现方法: (1)将“字符屏幕”与程序中的一个二维字符数组建立对应关系。如,本程序的rose数组就对应于欲显示的“字符屏幕”,其中的rose[0][0]表示“字符屏幕”的左上角点,而rose[y][x]则表示“字符屏幕”的第y+1行第x+1列的那一个点(y值即行号由上往下扩展, x值即列号由左往右扩展)。 (2)将二维字符数组的各元素均置为“空”(对应于一个“空白字符屏幕”)。 (3)按某种计算方法(或计算公式)算出应该在“字符屏幕”的哪些位置处“画点”(通过往对应字符数组的某些元素处置“*”符号来完成)。 (4)将已准备好的当前字符数组显示到“字符屏幕”上(在“字符屏幕”上“画”出了所需图形)。
3 本例的具体实现方法: 把360度分为足够多的若干份(本例分为128份),在每个分定的角度angle处,按照上述的极坐标方程,计算出每一个对应的函数值p(即极径),从而得到平面上的一批点;将这批平面点对应到“字符屏幕”上(相应的rose数组中),并将每一个点用一个字符“*”来表示并显示到屏幕上(“字符屏幕”上的其他点均显示为“空”)。
#include <iostream.h> #include <math.h> //use “sin”、“cos” main(){ const int maxY=22; //“字符屏幕”的最大行数(书中为25) const int maxX=70; //“字符屏幕”的最大列数(书中为80) const float pai=3.14159, a=12.0; //a表示所画图形中,矩极点的最长距离(书中为16.0) const int aspect=2; //屏幕字符“高:宽”为2:1,生成曲线时,每点的x要乘以2