第五周
1.数组的概念
- 可以用来表达类型相同的元素的集合,集合的名字就是数组名。
- 数组里的元素都有编号,元素的编号叫下标。通过数组名和下标,就能访问元素。
- 一维数组的定义方法如下:
类型名 数组名[元素个数]; - 其中“元素个数”必须是常量或常量表达式,不能是变量,而且其值必须是正整数。元素个数也称作“数组的长度”。
T a[N];
-
T是类型名,如
int
double
string
;N为正整数或者值为正整数的常量表达式。 -
数组a有N个元素,每个元素都是一个类型为T的变量。N个元素在内存里是一个挨一个连续存放的。a数组占用大小总共为
N × sizeof(T)
字节的存储空间。 -
表达
sizeof(a)
的值就是整个数组的体积,即N × sizeof(T)
。
int a[100];
//名字为a的数组,有100个元素,每一个元素都是一个int型的变量。
- 数组下标从0开始,N个元素的数组,下标从0 至 N-1。
- 数组名a代表数组的地址,假设为p,则变量
a[i]
的地址就是
p+i*sizeof(int)
。
例题:接收键盘输入的100个整数,然后将它们按和原顺序相反的顺序输出。
self:
#include<iostream>
using namespace std;
int a[100];
int main(){
for(int i=0;i<100;++i)
cin>>a[i];
for(int i=99;i>-1;--i)
cout<<a[i];
return 0;
}
teacher:
#include <iostream>
using namespace std;
#define NUM 100 //使用符号常量,便于修改
int a[NUM]; //数组一般不要定义在main里面,尤其是大数组
int main() {
for(int i = 0;i < NUM; ++i)
cin >> a[i];
for(int i = NUM-1;i >= 0; --i)
cout << a[i] << " ";
return 0;
}
- 数组一般不要定义在main里面,尤其是大数组。
2.数组的初始化
- 在定义一个一维数组的同时,就可以给数组中的元素赋初值:
类型名 数组名[常量表达式]={值,值……值}; - { }中的各数据值即为各元素的初值,值之间用逗号间隔。
- 数组初始化时,{ }中值的个数可以少于元素个数。相当于只给前面部分元素赋值,而后面的元素,其存储空间里的每个字节都被写入二进制数0。
- 数组初始化时,若常量表达式为空,那么值有几个,常量表达式为几。
//正常
int a[4]={1,2,3,4};
//值缺少
int a[4]={1,2};//等价于 int a[4]={1,2,0,0};
//常量表达式缺少
int a[]={1,2,3,4};//等价于 int a[4]={1,2,3,4};
例题:筛法求素数
- 判断一个数n是不是素数,可以用2到 之间的所有整数去除n,看能否整除。如果都不能整除,那么n是素数(慢)。
- 筛法求素数:把2到n中所有的数都列出来,然后从2开始,先划掉n内所有2的倍数,然后每次从下一个剩下的数(必然是素数)开始,划掉其n内的所有倍数。最后剩下的数,就都是素数。
#include<iostream>
using namespace std;
#define MAX_NUM 100000
char isPrime[MAX_NUM+10];
int main(){
for(int i=2;i<=MAX_NUM;i++)
isPrime[i]=1;
for(int i=2;i<=MAX_NUM;i++){
if(isPrime[i])
for(int j=2*i;j<=MAX_NUM;j+=i)
isPrime[j]=0;
}
for(int i=2;i<=MAX_NUM;i++){
if(isPrime[i])
cout<<i<<" ";
}
return 0;
}
//bool
#include<iostream>
using namespace std;
#define MAX_NUM 10000000
bool isPrime[MAX_NUM+10];
int main(){
for(int i=2;i<=MAX_NUM;i++)
isPrime[i]=true;
for(int i=2;i<=MAX_NUM;i++){
if(isPrime[i])
for(int j=2*i;j<=MAX_NUM;j+=i)
isPrime[j]=false;
}
for(int i=2;i<=MAX_NUM;i++){
if(isPrime[i])
cout<<i<<" ";
}
return 0;
}
3.用数组取代复杂分支结构
有时会用一个数组存放一些固定不变的值,以取代复杂的程序分支结构。
例题:星期问题
1.简单
接受一个整数作为输入,如果输入1,则输出“Monday”,输入2,则输出“Tuesday”……输入7,则输出“Sunday”,输入其他数,则输出“Illegal”。
#include<iostream>
#include<string.h>
using namespace std;
string a[8]= {"","Monday","Tuesday","Wednesday","Thursday",
"Friday","Saturday","Sunday"
};
int main() {
int c;
cin>>c;
if(c<0||c>7) printf("illegal");
else cout<<a[c];
return 0;
}
2.复杂
例题: 已知2012年1月25日是星期三,编写一个程序,
输入用“年 月 日”表示的一个2012年1月25日以后的期,
输出该日期是星期几(星期天输出0)。
self:
#include<iostream>
using namespace std;
int month[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
int main() {
int Y,M,D,days=0;
cin>>Y>>M>>D;
for(int i=2012; i<Y; ++i) {//注意小于号
if(i%4==0&&i%100!=0||i%400==0)
days+=366;
else days+=365;
}
if(Y%4==0&&Y%100!=0||Y%400==0)
month[2]=29;
for(int i=1; i<M; ++i) {
days+=month[i];
}
days+=D;
days-=22;
cout<<(days%7);
return 0;
}
teacher:
#include <iostream>
using namespace std;
int monthDays[13] = {-1,31,28,31,30,31,30,31,31,30,31,30,31};
int main()
{
int year,month,date;
int days = 0; //从2012-01-22开始过了多少天
cin >> year >> month >> date;
for(int y = 2012; y < year; ++y) {
if( y%4 ==0 && y%100!= 0 || y%400 == 0)
days += 366;
else
days += 365;
}
if( year%4 ==0 && year%100!= 0 || year%400 == 0)
monthDays[2] = 29;
for(int m = 1; m < month; ++m)
days += monthDays[m]; 36
days += date;
days -= 22; //2012年1月22日是星期天
cout << days % 7 << endl;
return 0;
}
4.数组越界
int a[10];
- 在c语言或者c++语言中,数组元素的下标,可以是任何整数,可以是负数,也可以大于数组的元素个数。不会导致编译错误,但运行时很可能会出错!!!因为可能写入了别的变量的内存空间,或者写入指令的内存空间。
- 用变量作为数组下标时,不小心会导致数组越界(变量下标值变为负数,或者太大),可能引起意外修改其他变量的值,导致程序运行结果不正确。可能试图访问不该访问的内存区域,导致程序崩溃。
- 数组越界的程序,用某些编译器编译后可能可以正确运行,换一个编译器编译后就运行错误。
5.二维数组概念
-
定义N行M列的二维数组:
T a[N][M];
-
T :类型名,如char , double, int…
-
N、M : 正整数,或值为正整数的常量表达式。
-
数组占用了一片连续的、大小总共为 N×M×sizeof(T)字节的存储空间。
-
表达
sizeof(a
的值就是整个数组的体积,即N×M×sizeof(T)。 -
行下标和列下标都从0开始,到N-1和M-1结束。
-
访问数组元素的方法:
数组名[行下标][列下标]
6.二维数组的存放方式
int a[2][3]
在内存中的存放方式:
- 二维数组的每一行,实际上都是一个一维数组。
- 数组T a[N][M] 每一行都有M个元素
- 第i行的元素就是
a[i][0]
、a[i][1]
……a[i][M-1]
同一行的元素,在内存中是连续存放的。 - a[0][0]是数组中地址最小的元素。如果
a[0][0]
存放在地址n,则a[i][j]
存放的地址就是:n + i × M× sizeof(T) + j × sizeof(T)
7.二维数组的初始化
- 在定义一个一维数组的同时,就可以给数组中的元素赋初值:
类型名 数组名[常量表达式][常量表达式]={{值组}{值组}……{值组}};
- 每个内层的{},初始化数组中的一行。
- 二维数组初始化时,如果对每行都进行了初始化,则也可以不给出行数。
//正常
int a[2][3]={ {80,75,92},{61,65,0} };
//等价于
int a[][3]={ {80,75,92},{61,65} };
//会自动补全行数为2,而a[1][2]会被初始化为0。
8.二维数组的遍历
#define ROW 20
#define COL 30
int a[ROW][COL];
for( int i = 0; i < ROW ; ++i) {
for( int j = 0; j < COL ; ++j )
cout << a[i][j] << " ";
cout << endl;
}
例题:矩阵乘法
编程求两个矩阵相乘的结果。输入第一行是整数m,n,
表示第一个矩阵是m行n列的。接下来时一个m×n的矩阵。
再下一行的输入是整数p,q,表示下一个矩阵是p行q列(n=p)
再接下来就是一个p行q列的矩阵。
要求输出两个矩阵相乘的结果矩阵(1 < m,n,p,q <= 8)。
#include<iostream>
using namespace std;
#define ROW 8
#define COL 8
int a[ROW][COL];
int b[ROW][COL];
int c[ROW][COL];
//提前开大数组,可以避免在运用中数组的常量表达式是变量。
int main(){
int m,n,p,q;
cin>>m>>n;//二重循环写入a数组
for(int i=0;i<m;i++){
for(int j=0;j<n;j++)
cin>>a[i][j];
}
cin>>p>>q;//二重循环写入b数组
for(int i=0;i<p;i++){
for(int j=0;j<q;j++)
cin>>b[i][j];
}
for(int i=0;i<m;i++){
for(int j=0;j<q;j++){
c[i][j]=0;//对a,b数组进行矩阵乘法
for(int k=0;k<n;k++)
c[i][j]+=a[i][k]*b[k][j];
}
}
for(int i=0;i<2;i++){//输出c数组
for(int j=0;j<3;j++){
cout<<c[i][j]<<" ";
}
cout<<endl;//给一行进行换列
}
return 0;
}