640 likes | 723 Views
第七章 数组. C 语言不仅提供了基本类型的数据,还提供了构造类型的数据:它们是数组类型、构造体类型、共用体类型。 本章只介绍数组。数组是有序数据的集合。数组中的每一个元素都属于同一个数据类型。用一个统一的数组名和下标来唯一地确定数组中的元素。. §7.1 一维数组的定义和引用. 一、一维数组的定义 格式: 类型说明符 数组名 [ 常量表达式 ] 例如: int a[10]; float b[5]; char c[10] 说明: 1 、数组名与变量名命名规则相同,代表内存中连续区域的首地址。. 2 、下标的常量表达式应用 [ ] ,而不是()、 { }
E N D
第七章 数组 C语言不仅提供了基本类型的数据,还提供了构造类型的数据:它们是数组类型、构造体类型、共用体类型。 本章只介绍数组。数组是有序数据的集合。数组中的每一个元素都属于同一个数据类型。用一个统一的数组名和下标来唯一地确定数组中的元素。
§7.1 一维数组的定义和引用 • 一、一维数组的定义 • 格式:类型说明符 数组名[常量表达式] • 例如:int a[10]; float b[5]; char c[10] • 说明: • 1、数组名与变量名命名规则相同,代表内存中连续区域的首地址。
2、下标的常量表达式应用[ ],而不是()、{ } • 3、[ ]中必是常量表达式,是常量或符号常量 不能是变量。 • 例如:int n; • scanf(“%d”,&n); int a[n];是错误的! • 4、[ ]中表示数组元素的个数,是从a[0]开始 的,而不是从a[1]开始的。若int a[5]则数 组中元素应是:a[0],a[1],a[2],a[3],a[4],而没 有a[5]存在,且在内存中的顺序是固定的。
int a[5] 每个元素占两个字节 • 5、数组名不能与变量同名,否则出现 逻辑错误。
二、一维数组的引用 • 格式:数组名 [下标] • 说明: • 1、数组必须事先有定义,和变量一样 • 2、下标用[ ]表示,其中可以用常量表达式,也 可用变量表达式,但必须为整型! a[3]=b[1]+b[0]; scanf(“%d”,&n);a[n]=a[3]+a[8]; • 3、在C语言中,下标的取值范围是从[0,元素 个数-1]结束。 例如:向一个数组中由小到大存入9个数然 后按由大到将9个数显示出来。
例7、1 数组元素的引用 结果为:9 8 7 6 5 4 3 2 1 0 以上是利用一段程序向数组赋值,这样会占用运行时间,下面看一下如何在程序运行前,将数组中元素赋值。 • 程序如下: • main() • { • int i,a[10]; • for(i=0;i<=9;i++) • a[I]=i; • for(i=9;i>=0;i- -) • printf(“%d ”,a[i]); • }
三、一维数组的初始化 • 1、定义数组时初始化: int a[10]={0,1,2,3,4,5,6,7,8,9}; • 2、给一部分元素赋值: int a[10]={0,1,2,3,4};其余元素的值均为0。 • 3、全部元素为0: int a[10]={0,0,0,0,0,0,0,0,0,0}; 或int a[10]; 或int a[10]={0}; • 4、不指定数组的长度:(一般用于对全部 数组元素都赋初值时) 例如: int a[ ]={1,2,3,4,5};
四、一维数组应用举例: • 例7、2 求Fibonacci数列,只求前20个数。 • f1=1; f2=1 • f3=f1+f2=2 • f4=f2+f3=3 • f5=f3+f4=5 ………… fi=f(i-2)+f(i-1) • 可以将20个数值求出依次放入a[20]数组的20个元素中去,在按着5个一行打印出来。
程序如下: • main( ) 改后 • { • int f[20]={1,1}; • int i; • for(i=2;i<=20;i++) • f[i]=f[i-2]+f[i-1]; • for(i=0;i<20;i++) • {if(i%5==0) printf(“\n”); • printf(“%12d”,f[i]);} • }
一维数组应用举例-------排序 选择排序 直接插入排序 插入排序 二分插入排序 shell排序(希尔排序) 起泡排序
一、选择排序 (每趟选出一个最小元素.用第一个元素去与其他元素一一相比较,将指针指向较小的元素,最小的换到前面) 例如:将以下六个整数按由小到大的顺序排列. a[0] a[1] a[2] a[3] a[4] a[5] 172 168 180 176 163 175
a[0] a[1] a[2] a[3] a[4] a[5] 172 168 180 176 163 175 第一趟 pointer pointer pointer
a[0] a[1] a[2] a[3] a[4] a[5] 163 168 180 176 172 175 第一趟 结束
a[0] a[1] a[2] a[3] a[4] a[5] 163 168 180 176 172 175 第二趟 pointer
a[0]) a[1] a[2] a[3] a[4] a[5] 163168 180 176 172 175 第二趟 结束
a[0] a[1] a[2] a[3] a[4] a[5] 163168 180 176 172 175 第三趟 pointer pointer pointer
a[0] a[1] a[2] a[3] a[4] a[5] 163168172 176 180 175 第三趟 结束
a[0] a[1] a[2] a[3] a[4] a[5] 163168172 176 180 175 第四趟 pointer pointer
a[0] a[1] a[2] a[3] a[4] a[5] 163168172175 180 176 第四趟 结束
a[0] a[1] a[2] a[3] a[4] a[5] 163168172175 180 176 第五趟 pointer pointer
a[0] a[1] a[2] a[3] a[4] a[5] 163168172175176 180 第五趟 结束
一趟比较 一趟结束对调
main( ) {int i,j,pointer,a[6]; for(i=1;i<=5;i++) for (i=0;i<=5;i++) printf(“%d ”,a[i]); scanf(“%d “,&a[i]); } for( i=0;i<=5-1;i++) { pointer=i; 程序演示 for( j=i+1;j<=5;j++) { if (a[j]<a[pointer] pointer=j; if (i!=pointer ) 交换 a[i],a[pointer];}}
二、插入排序 1、直接插入排序 第一个不动,从第二个起逐一插入以排序数列合适位置。 A[1] a[2] a[3] a[4] a[5] a[6] 172 168 180 176 163 175 168 172 180 176 163 175 168 172 180 176 163 175 168 172 176 180 163 175 163 168 172 176 180 175 163 168 172 175 176 180
for( i=2;i<=n;i++) { x=a[i]; j=i-1; while(j>0&&x<a[j]) { a[j+1]=a[j] ; j=j-1 ; } a[j+1]=x ; } for( i=1;i<=n;i++) printf(“%d ”, a[i]); 程序演示 168 172 176 180 163 175 x
2、二分插入排序 使用二分查找法查找插入位置。
3、shell 排序 取一个整数增量d1<n,相隔d1的作为一组,组内排序。再取 d2<d1,直到di=1。 di 选法有多种,最初选法d1=int(n/2)、d2=int(d1/2)…… n=9 d=4 49 38 65 97 76 13 27 55 89 d=2 49 13 27 55 76 38 65 97 89 d=1 27 13 49 38 65 55 76 97 89 13 27 38 49 55 65 76 89 97
{int n=5; int a[6],i,j,x ,g; for(i=1;i<=n;i++) {scanf(“%d”,a[i]); printf(“%d”,a[i]); }printf(“\n”); d=(int)(n/2); while(d>=1) {for( g=1;g<= d;g++) {for(i=d+g;i<= n;i+=d) { x=a[i]; j=i-d; while( j>0) {if(x<a[j]) {a[j+d]=a[j];j=j-d;} }} a[j+d]=x;} d=(int)(d/2);} for(i=1;i<=n;i++) printf(“%d”,a[i]);} }
三、起泡排序 第一轮:从1到n ,比较相邻两元素,逆序则交换。 第二轮:从1到n-1,比较相邻两元素,逆序则交换。 …… 第n-1轮:从1到2,比较相邻两元素,逆序则交换。 第一轮: 第二轮: 第三轮: 第四轮: 3 1 5 7 9 1 3 5 7 9 7 5 3 9 1 5 3 7 9 1 5 3 7 9 1 5 3 7 1 9 5 3 7 1 9 3 5 7 1 9 3 5 7 1 9 3 5 1 7 9 3 5 1 7 9 3 5 1 7 9 3 1 5 7 9 5 7 3 9 1
main( )演示 { int a [ 6] ; for ( i=1; i<=5 ;i++) scanf(“%d “,&a[i]) ; for (i=1;i<=5-1; i++) { for (j=1;j<=5-i;j++) if( a[j]>a[j+1]) { SWAP a[j],a[j+1] } } for( i=1;i<= 5;i++) printf(“%d “, a[i]) ; }
例7、3 用起泡法排序:对7个数进行由小到大排序。 • 基本思路:将相邻的两个数比较,把小的调换到前面。 比如有2 8 5 7 0 1 4这七个数。
总结: • 7个数共比较了7-1趟, • 每趟分别比较了7-1,7-2,7-3,7-4,7-5,7-6次。 • N个数应比较N-1趟, • 每趟分别应比较N-1,N-2,N-3 • ……N-(N-1)=1次。
程序如下: for(j=1;j<=10-1;j++) for(i=1;i>=10-j;i++) if(a[i]>a[i+1]) {t=a[i];a[i]=a[i+1];a[i+1]=t;} printf(“the sorted numbers is:\n”); for(i=1;i<11;i++) printf(“%d ”,a[i]); } • main( ) • { • int a[11]; • int i,j,t; • printf(“please input ten nember:\n”); • for (i=1;i<=11;i++) • scanf(“%d”,&a[i]); • printf(“\n”);
数据排序在很多时候都会用到,例数据库中、线性搜索中,求平均效率为n/2,然而折半搜索的平均效率要高于冒泡排序。数据排序在很多时候都会用到,例数据库中、线性搜索中,求平均效率为n/2,然而折半搜索的平均效率要高于冒泡排序。
§7.2 二维数组的定义和引用 • 简单变量是一个点;一维数组描述的是一条线上的点;二维数组是指一个面上的点。一个队列的问题,可以将每一个队列定义为一个一维数组。可如果我们来描述一个由一行一行队列组成的方阵,怎么办呢?只好将一行定义成一个数组,每个数组得起成不同的名称,这样真是麻烦! • 在C语言中对这样的方阵可以用一个二维数组来表示。
一、二维数组的定义 • 格式: 类型说明符 数组名[常量表达式][常量表达式] • 例如:int a[3][4]; float b[5][10]; 表明已经定义整型的二维数组,共3行, 4 列元素,分别是: • 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]
上面的这块内容共有3行,我们可以将每一行看成一个整体,那么相当于这块内容是由3个类型相同的元素组成,我们可以给这块内容起一个名字a,这块内容是由a[0],a[1],a[2]三个部分组成。其中a[0],a[1],a[2]又可以看作是每一部分的名称,而每一部分我们又可以看成是由4个类型相同的元素组成,那么每一部分又可以看做是一个一维数组。这样来形容二维数组在用指针对数组进行处理时非常有用。上面的这块内容共有3行,我们可以将每一行看成一个整体,那么相当于这块内容是由3个类型相同的元素组成,我们可以给这块内容起一个名字a,这块内容是由a[0],a[1],a[2]三个部分组成。其中a[0],a[1],a[2]又可以看作是每一部分的名称,而每一部分我们又可以看成是由4个类型相同的元素组成,那么每一部分又可以看做是一个一维数组。这样来形容二维数组在用指针对数组进行处理时非常有用。 • 由于内存在表示数据时只能按照线性方式存放,所以二维数组中各元素在存放到内存中时也只能按线性方式存放。C语言规定,二维数组中的元素在存储时先存放第一行的数据,再存放第二行的数据等等。每行数据按下标规定的顺序由小到大的存放。这样上面的a数组就是按下面的方式存入内存的,我们假设a数组的内存起始地址为1000:
二、多维数组的定义 • 另外,在C语言中还存在多维数组的概念,假如我们要定义一个四维数组,可以这样定义: int a[3][2][2][2]; • 多维数组在内存中存放有这样有原则: 1、先存放a[0][0][0][0],即让下标全都取0。 2、然后存放的元素是使最右边下标变化,即 加1的那个元素,依此类推,直到右边的下标变化完毕(取到最大值)。 3、然后存放的元素是使右边倒数第二个下标变化。每一次变化,都使此位置右边的下标变化。
4、然后存放的元素是使右边倒数第三个下标变化。 每一次变化,都使此位置右边的下标变化。 • 5、然后存放的元素是使右边倒数第四个下标变化。每一次变化,都使此位置右边的下标变化。
三、二维数组的引用 • 格式: 数组名[下标][下标] • 二维数组的引用和一维数组的引用基本上是 一致的。只不过多了一个下标而矣,至于多 维数组也是一样的。 • 注意int a[4][5]和a[4][5]的区别: • 前者是定义了一个四行五列的数组,只可以 引用到a[3][4],而没有a[4][5]这个元素。 • 后者是元素a[4][5],定义数组时最小也应是 a[5][6]。
四、二维数组的初始化 • 1、分行初始化 int a[3][4]={{1,2,3,4},{6,7,4,8},{1,3,5,6}}; • 2、线性初始化 int a[3][4]={1,2,3,4,6,7,4,8,1,3,5,6}; • 3、部分元素赋初值 int a[3][4]={{1},{4,3},{1,2}}; int a[3][4]={{1},{4}}; int a[3][4]={{1},{},{0,0,3}}; • 4、全部赋值 int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int a[][4]={{1},{},{4}};
五、二维数组程序举例 • 例7、4 将二维数组元素行、列互换,存到另一 数组中。
程序如下: printf(“\n”);} printf(“array b:\n”); for (i=0;i<=2;i++) {for (j=0;j<=1;j++) printf(“%5d”,b[i][j]); printf(“\n”);} } • main( ) { • int a[2][3]={1,2,3,4,5,6}; • int b[3][2],i,j; printf(“array a:\n”); • for (i=0;i<=1;i++) {for(j=0;j<=2,j++) {printf(“%5d”,a[i][j]); b[j][i]=a[i][j];}
例7.5 有一3×4 的矩阵,求一个二维数组中 元素最大的元素的值,及其下标。 • 程序如下: • main( ) { • int i,j,row=0,col=0,max; • int a[3][4]={1,2,3,4,9,8,7,6,-10,10,-5,2}; max=a[0][0]; • for(i=0;i<=2;i++) • for(j=0;j<=3;j++) if(a[i][j]>max) {max=a[i][j];row=i;col=j;} printf(“max=%d,row=%d,col=%d\n”,max,row,col); }
§7.3 字符数组 • 用来存放字符的数组就是字符数组。这一节我们来学习字符数组,根据前面我们学习的内容,字符数组是用来存放字符数据的。它本身是一个数组,具有数组的全部特性,只不过是数组元素的类型是字符型的。
一、字符数组的定义 • 格式:char 数组名[常量表达式] 由于char和int类型相通,所以: char c[10]int c[10] 但浪费空间 c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9] C □ p r o g r a m \0
二、初始化 • 1、char a[10]={‘I’,’ ’,’a’,’m’,’ ’,’h’,’a’,’p’,’p’,’y’}; • 2、部分赋值 char a[8]={‘h’,’a’,’p’,’p’,’y’};其余未赋值的为空,’\0’ • 3、省略数组长度 char a[]={‘h’,’a’,’p’,’p’,’y’}; cccc • 4、对于二维的字符数组 char diamond[5][5]={{‘’,’’,’*’,’’,’’},{‘’,’*’,’’,’*’,’’}, {‘*’,’’,’’,’’,’*’},{‘’,’*’,’’,’*’,’’},{‘’,’’,’*’,’’,’’}}; • for(i=0;i<=4;i++) for(j=0;j<=4;j++) printf(“%c”,diamond[i][j]); printf(“\n”);
三、引用 • main( ) cccc • { int i; • char c[10]={‘I’,’’,’a’,’m’,’’,’h’,’a’,’p’,’p’,’y’}; for(i=0;i<10;i++) printf(“%c”,c[i]); printf(“\n”);}