C语言程序设计 课件 第4章数组_第1页
C语言程序设计 课件 第4章数组_第2页
C语言程序设计 课件 第4章数组_第3页
C语言程序设计 课件 第4章数组_第4页
C语言程序设计 课件 第4章数组_第5页
已阅读5页,还剩165页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

《程序设计》1第4章数组算法+数据结构=程序(1)算法编程解决问题的方法数据结构现实世界中要被处理的信息在程序中的表示形式《程序设计》2算法+数据结构=程序(2)程序设计语言数据结构基本的数据类型:整数、实数、字符复杂数据:数组、指针、结构算法通过顺序结构、选择结构、循环结构和函数来实现;选择结构:if选择结构和switch选择结构;循环结构:while循环结构,do-while循环结构和for循环结构。《程序设计》3《程序设计》4C语言中的复杂数据说明复杂数据是由若干基本数据或其它复杂数据按一定的方法(规则)构造而成的(也称“导出类型”)C语言包含的构造复杂数据类型的构造机制有数组、结构和指针。利用这几种构造手段,能在基本数据类型、指针等类型基础上,通过反复应用C语言提供的构造手段,使程序能描述各种复杂的数据结构说明或定义复杂数据必须指出它的成分元素的类型、成分个数和构造方法。对于复杂类型的变量来说,重点是访问它的元素的方法《程序设计》54.1数组的基本概念4.2一维数组4.3多维数组4.4字符串处理技术基础目录4.1数组的基本概念为什么需要数组?问题:向计算机输入全班50个学生一门课程的成绩。解决:用50个float型变量表示学生的成绩?烦琐,如果有1000名学生怎么办呢?没有反映出这些数据间的内在联系,这些数据是同一个班级、同一门课程的成绩,具有相同的属性利用数组处理批量数据《程序设计》6《程序设计》74.1数组的基本概念数组是由若干同类元素组成的对象数组的每个元素的数据类型相同,元素个数固定,其元素按顺序存放,每个元素对应一个序号(称为下标),各元素按下标存取(引用)数组元素的存储顺序与其下标相对应,数组元素的下标从0开始顺序编号《程序设计》-2008年秋8数组概念说明数组元素在数组中的下标是固定不变的,而数组元素是变量,其值是可以变化的。数组元素变量与相同类型的独立的变量一样使用程序引用数组元素变量借助于数组定义时为元素变量隐含设定的下标引用数组元素变量所需的下标个数由数组的维数决定,数组有一维数组、二维数组或多维数组之分《程序设计》-2008年秋9数组举例一行正文可以表示成由字符组成的数组

chars[120];/*字符数组*/一个整数向量可以表示成由整数组成的数组

intintVector[80];/*由80个整数组成的数组*/一个矩阵就可以表示成由向量构成的数组

doublematrix[40][50];/*40行X50列实数矩阵*/学生成绩表可表示成由学生成绩单组成的数组

intscore[40][7];/*40名学生课程成绩,每个学生学7门课程*/4.2一维数组一维数组定义一维数组元素的引用数组初始化一维数组程序实例冒泡排序《程序设计》10《程序设计》114.2.1

一维数组定义定义形式:

类型说明符数组名[常量表达式];类型说明符用来指明数组元素的类型,同一数组元素的类型相同数组是一个变量,用标识符命名,数组名遵守标识符的命名规则方括号“[]”是数组的标志,其中的常量表达式的值表示数组的元素个数,即数组的长度常量表达式通常是整型常量、符号常量或sizeof(类型名),以及由它们组成的常量表达式C语言约定,当数组名单独在程序中使用时,数组名可以代表为它分配的内存区域的开始地址,即数组中下标为0的元素的地址【例4.2.1.1】一维数组示例:inta[10];《程序设计》12类型说明符用来指明数组元素的类型,同一数组元素的类型相同,如上例“int”;数组是一个变量,用标识符命名,数组名遵守标识符的命名规则,如上例“a”;方括号“[]”是数组的标志,其中的常量表达式的值表示数组的元素个数,即数组的长度。常量表达式通常是整型常量、符号常量或sizeof(类型名),以及由它们组成的常量表达式,如上例,方括号“[]”内的“10”。数组元素的下标从0开始,直至数组元素的个数减一,如上例,下标最后到9(10-1)。《程序设计》13【例4.2.1.1】一维数组示例inta[10]={35,27,49,18,60,54,77,83,41,2};《程序设计》144.2.2一维数组元素的引用只能引用数组中的元素,而不能一次整体调用整个数组全部元素的值引用形式:数组名[下标]

例如,inta[5];数组a的5个元素可分别用a[0],a[1],a[2],a[3],a[4]来引用如

a[4]=a[0]+a[1]+a[2]+a[3];

a[0]=a[i+z];/*如果0<=i+z<5*/《程序设计》15一维数组元素的引用示例设有定义:intx[20],i;顺序输入数组x的全部元素

printf("Enterdataforarrayx[].\n");for(i=0;i<20;i++)scanf("%d",&x[i]);

顺序输出x的全部元素

for(i=0;i<20;i++)printf("%d\t",x[i]);《程序设计》16【例4.2.2.2】一维数组元素的引用示例设仍有定义:intx[20],i;分别统计数组x中大于、等于和小于0的元素个数

great=equal=less=0;for(i=0;i<20;i++)if(x[i]>0)great++;elseif(x[i]==0)equal++;elseless++;《程序设计》17【例4.2.2.3】一维数组定义及元素引用程序样例#include<stdio.h>voidmain(){inti,digits[10];for(i=0;i<10;++i)digits[i]=i;for(i=0;i<5;++i)printf("%3d",digits[2*i]);printf("\n");for(i=0;i<5;++i)printf("%3d",digits[2*i+1]);printf("\n\n\n");}程序运行结果

0246813579

【例4.2.2.4】EcologicalPremium试题来源:TheJointEffortContest(WeandRodrigoMalta),2002在线测试:UVA10300农场主要根据他们农场的条件支付费用。支付费用的简化规定如下:已知每个农场主的农场的面积(平方米);在农场里的动物的数量,这里对不同的动物不做区分;以及环境友好系数,用一个大于零的整数表示。农场主支付的费用基于对这些参数进行计算:首先,计算每头动物平均占据的平均面积;然后,这个平均面积(以平方米为单位)乘以环境友好系数,得出农场主为每头动物支付的费用。这样,农场主支付的费用,是将农场主为每头动物支付的费用乘以动物的数量。输入输入的第一行给出一个正整数n(<20),表示测试用例的数量。每个测试用例的第一行给出一个整数f(0<f<20),表示测试用例中农场主的数量。在这一行之后,每位农场主一行,每行包含三个正整数:以平方米为单位的农场的面积,在农场里的动物的数量,以及表示环境友好系数的整数值。输入在文件结束时终止。输入中没有大于100000或小于0的整数。输出对于每个测试用例,输出一行,给出一个整数,表示在该测试用例中农场主们的要支付的费用的总数。不要输出任何空行。试题解析根据题目描述,可以推导出,每个农场主支付的费用是农场的面积乘以环境友好系数;而农场主们的要支付的费用的总数,就是每个农场主支付的费用的总和。也就是说,在输入中给出的农场里的动物的数量没有用处。对于每个测试用例,用3个一维整型数组a,b,c,分别表示农场的面积,农场里的动物的数量,环境友好系数这3组批量数据。由于输入说明中已经给出了每个测试用例的农场主数量f的上限(0<f<20),所以,数组元素个数定为20。外层循环,每次循环处理一个测试用例。对于每个测试用例,首先,农场主们的要支付的费用的总数sum初始化为0,并输入当前测试用例的农场主数量f;然后,进入内层循环,每次循环,输入一位农场主的数据:农场的面积,在农场里的动物的数量,以及环境友好系数;并把农场的面积和环境友好系数相乘后,累加到sum中。《程序设计》244.2.3数组初始化数组定义的初始化或数组初始化指的是数组定义同时给出元素初值的表述形式数组初始化形式有数组定义时,顺序列出数组全部元素的初值只给数组的前面一部分元素设定初值当对数组的全部元素都明确设定初值时,可以不指定数组元素的个数《程序设计》25数组初始化示例-1数组定义时,顺序列出数组全部元素初值例如:intd[5]={0,1,2,3,4};将数组元素的初值依次写在一对花括弧内,等价于:

d[0]=0;d[1]=1;d[2]=2;d[3]=3;d[4]=4《程序设计》26数组初始化示例-2只给数组的前面一部分元素设定初值例如:inte[5]={0,1,2};定义数组e有5个整型元素,其中前3个元素设定了初值,而后2个元素未明确地设定初值系统约定,当一个数组的部分元素被设定初值后,对于元素为数值型的数组,那些未设定初值的元素自动被设定0值。所以数组e的后2个元素的初值为0但是,当定义数组时,如未对它的元素指定过初值,对于内部的局部数组,则它的元素的值是不确定的《程序设计》27数组初始化示例-3当对数组的全部元素都明确设定初值时,可以不指定数组元素的个数例如:intg[]={5,6,7,8,9};由花括号内的初值个数确定数组的元素个数若提供的初值个数小于数组希望的元素个数时,则方括号中的数组元素个数不能省略例如:intb[10]={1,2,3,4,5}数组b有10个元素,前5个如设定所示,后5个都为0注意:初值个数不允许超过数组元素个数例如:intc[5]={0,1,2,3,4,5};是错误的代码《程序设计》28【例4.2.3.1】Fibonacci数列Fibonacci数列是一个自然数的序列,定义如下:F1=1;F2=1;Fn=Fn-1+Fn-2,其中n>2。编写程序,用数组计算Fibonacci数列的前30项值。利用数组存储Fibonacci数列的各项值,其中,数列的前2项可用初值为它设定。《程序设计》29Fibonacci数列(续)#include<stdio.h>#defineMAXN30#defineAline10voidmain(){longf[MAXN]={1L,1L};intk;

for(k=2;k<MAXN;k++)f[k]=f[k-2]+f[k-1];for(k=0;k<MAXN;k++){if(k%Aline==0)/*每行输出Aline个数*/printf(“\n”);printf(“%8ld”,f[k]);}printf(“\n”);}【例4.2.3.2】FibonacciBase在线测试:UVA948众所周知,Fibonacci数列是从0和1开始,然后,将最后两个数字相加得到下一个数字;即f(n)=f(n-1)+f(n-2),n

2。例如,数列中的第2个数字是1(1=1+0),第3个数字是2(2=1+1),第4个数字是3(3=2+1),依此类推。下图给出Fibonacci数列n

9的情形。Fibonacci数列在我们生活中出现在许多事情上,有着重要的意义。所有的正整数都可以表示为Fibonacci数列中的数字的和;而且,对于每个正整数,存在若干个不同的集合,每个集合由Fibonacci数列中的数字组成,集合中的数字的和等于该正整数。例如:13可以表示为集合{13},{5,8}或{2,3,8}中数字的和,17可以表示为集合{1,3,13}或{1,3,5,8}中的数字的和。一个正整数可以表示成Fibonacci二进制数anan-1…a2,其数值为an

f(n)+an-1

f(n-1)+……+a2

f(2),其中,an=1,而{an-1,……,a2}取值0或1。例如,正整数10可以表示为Fibonacci二进制数10010(fib),其数值计算方式如下:1

f(6)+0

f(5)+0

f(4)+1

f(3)+0

f(2)=1

8+0

5+0

3+1

2+0

1=10。一个正整数可以有多个Fibonacci二进制数表达,例如,6=5+1=1001(fib),而6又可以表示成6=3+2+1=111(fib)。因为任何两个连续的Fibonacci数的和就是下一个的Fibonacci数。为此,本题设定在集合中不能有两个连续的Fibonacci数,即Fibonacci二进制数中没有连续的1;这样,每个正整数就有一个唯一的Fibonacci二进制数表示。如上例,6被唯一地被表示为1001(fib)。再例如,17=100101(fib),如图所示。给出一个正整数的集合,请您将这些数表示成Fibonacci二进制数。输入输入的第一行给出一个数字n,表示后面给出多少个正整数(1

n

500)。然后给出n行,每行给出一个小于100000000的正整数。输出请您对输入中的n个整数中的每一个数输出一行,格式为“DECBASE=FIBBASE(fib)”,其中,DECBASE是给出的十进制的数,FIBBASE是以Fibonacci二进制数表示的数字。请参见样例输出。试题解析本题的理论基础是Zeckendorf(齐肯多夫)定理及其证明。定理4.2.1(Zeckendorf定理).

任何正整数都可以表示成若干个不连续的Fibonacci数(不包括第一个Fibonacci数)的和。证明:设f(n)是第n个Fibonacci数。采用数学归纳法证明。当m=1,2,3时,因为1=f(2),2=f(3),3=f(4),所以命题成立。假设对任何小于正整数m,命题成立。如果m是Fibonacci数,则命题对m也成立。如果m不是Fibonacci数,则存在n1,满足f(n1)<m<f(n1+1)。设m'=m-f(n1),则m'=m-f(n1)<f(n1+1)-f(n1)=f(n1-1),即m'<f(n1-1)。因为m'<m,所以由归纳假设,m'可以表示成若干个不连续的Fibonacci数的和,即m'=f(n2)+f(n3)+...+f(nt),其中n2>n3>...>nt,且n2,n3,...,nt是不连续的整数。又因为m'<f(n1-1),所以n2<n1-1,即n2与n1也是不连续的整数。所以,m=f(n1)+m',m=f(n1)+f(n2)+f(n3)+...+f(nt),其中n1>n2>n3>...>nt,且n1,n2,n3,...,nt是不连续的整数。因此,命题成立。■而对于正整数m,这样的和的表达式m=f(n1)+f(n2)+f(n3)+...+f(nt)也被称为m的齐肯多夫表示法,由定理4.2.1的证明,可以由贪心算法,即通过每次选取小于等于m的最大的Fibonacci数,得到m的齐肯多夫表示法。例如,本题中给出的17,小于等于17的最大的Fibonacci数是第7个Fibonacci数13,17-13=4;小于等于4的最大的Fibonacci数是第4个Fibonacci数3,4-3=1;小于等于1的最大的Fibonacci数是第2个Fibonacci数1,1-1=0;所以,17的齐肯多夫表示法是17=13+3+1;采用相应的Fibonacci二进制数表示,17=100101(fib)。由于每个测试用例都是小于100000000的正整数,而f(39)<100000000<f(40),而每个测试用例的计算都要基于Fibonacci数列;所以,在参考程序中,首先,计算Fibonacci数列,并存在数组f中;数组初始化intf[40]={0,1};然后,通过循环“for(i=2;i<40;++i)f[i]=f[i-1]+f[i-2];”计算在测试数据范围内Fibonacci数列。显然,数组f的下标就是相应的Fibonacci数的序号。然后,输入测试用例数n,每次循环处理一个测试用例正整数m:在Fibonacci数列中,从高到低,找到第一个不大于自己的Fibonacci数f[i],得到新的m=m-f[i],并且相应的Fibonacci二进制数位赋值1(如果当前的Fibonacci数大于m,则相应的Fibonacci二进制数位赋值0);然后重复这一步骤。【例4.2.3.2】FibonacciBase的参考程序,预先计算在测试数据范围内Fibonacci数列,这样的做法,被称为离线计算方法。离线计算方法在处理多个测试用例的过程中,预先计算出指定范围内的所有解,存入某个常量数组;以后每测试一个测试用例,直接从常量数组中引用相关数据就可以了。4.2.4一维数组程序实例有限一维数组中元素是有限的有序一维数组中元素一个接一个存储同质一维数组中元素的类型相同//循环顺序处理,每次处理一个元素,下一次循环处理下一个元素《程序设计》43《程序设计》44【例4.2.4.1】在数组中找值等于变量key值元素的下标在数组中找值为key的元素,有多种解法直观解法设置哨兵法若已顺序存放,则用二分法《程序设计》45在数组中找值等于变量key值元素的下标-直观解法从数组的第一个元素开始,顺序查找至数组的末尾,若存在值为key的元素,程序就终止查找过程;若不存在值为key的元素,程序将找遍整个数组。程序段代码如下

for(i=0;i<n;i++)if(key==a[i])break;/*找到终止循环,若找到则i<n;否则i=n*/查找过程也可用以下代码来描述

for(i=0;i<n&&key!=a[i];i++);/*找到结束循环,若找到i<n;否则i=n*/假定每个元素的查找机会均等,则采用上述查找方法,查找的平均次数v为:v=(1+2+3+…+n)/n=(n+1)/2若在数组中没有指定值的元素,则需查找n次《程序设计》46在数组中找值等于变量key值元素下标-设置哨兵先在数组第n个元素的后面(如数组定义时已预留了空闲的元素),第n+1元素位置放入要寻找的值(设置了一个哨兵),然后再从第一个元素开始顺序寻找,这能简化寻找循环的控制条件

a[n]=key;for(i=0;key!=a[i];i++);/*若找到i<n;否则i=n*/这种写法,数组需多用一个元素,但程序比前一种更简单《程序设计》47在数组中找值等于变量key值元素下标-二分法假定数组a的元素已按它们的值从小到大的顺序存放,则二分法是更好的查找方法算法基本思想是对任意a[i]到a[j](i<=j)的连续一段元素,根据它们值的有序性,试探位置m=(i+j)/2上的元素,a[m]与key比较有三种可能结果,分别采取三种对策key=a[m];找到,结束查找key>a[m];下一轮的查找区间为[m+1,j]key<a[m];下一轮的查找区间为[i,m-1]当j<i时,区间[i,j]变为一个空区间,即表示在数组a中没有值为key的元素。由于每轮查找后,使查找区间减半,因此称为二分法查找。初始查找区间为i=0,j=n-1《程序设计》48在数组中找值等于变量key值元素下标-二分法(续)i=0;j=n-1;/*设定初始查找区间*/while(i<=j){m=(i+j)/2;if(key==a[m])break;elseif(key>a[m])i=m+1;elsej=m-1;}

/*找到时,i<=j,a[m]==key;否则i>j*/【例4.2.4.2】FinancialManagement试题来源:ACMMid-Atlantic2001在线测试地址:POJ1004,ZOJ1048,UVA2362Larry今年毕业,找到了工作,并赚了很多钱。但不知为何,Larry总感觉钱不够用。因此,Larry要用财务报表来解决他的财务问题:他要计算他能用多少钱。现在可以通过Larry的银行帐号看到他的财务状况。请您帮Larry写一个程序,根据过去12个月他每个月的收入,计算要达到收支平衡,每个月他平均能用多少钱。输入输入12行,每一行是一个月的收入,收入的数字是正数,精确到分,没有美元的符号。输出输出一个数字,是这12个月收入的平均值。精确到分,前面加美元的符号,后面加行结束符。在输出中没有空格或其他字符。试题解析【例4.2.4.3】Sub-prime试题来源:BrazilianNationalContest2009在线测试:UVA11679造成最近的经济危机的部分原因,是银行向无力偿还的人发放贷款,并将这些贷款作为债券转售给其他银行。显然,当人们无法偿还贷款时,整个系统就崩溃了。这场危机非常严重,影响了世界各国,包括Nlogonia。Nlogonia的ManDashuva总理要求中央银行主席拿出解决方案。中央银行主席想出了一个绝妙的主意:如果所有银行都只能用自己的货币储备来清算债券,那么所有银行都会生存下来,危机也就会避免。然而,涉及的债券和银行的数量很多,这是一项极其复杂的任务,因此中央银行主席请求您编写一个程序,根据银行及其印制的债券,确定是否所有银行都可以仅使用其货币储备和信贷偿还债务。输入输入由若干测试用例组成。每个测试用例的第一行给出两个整数b和n,分别表示银行的数量(1≤b≤20)和银行发行的债券的数量(1≤n≤20)。银行用从1到b的整数来标识。第二行给出用空格分隔的b个整数ri,表示b家银行中每家银行的货币储备(0≤bi≤104,1≤i≤b)。接下来的n行每行给出三个用空格分隔的整数:d,表示债务人银行(1≤D≤B);c,表示债权人银行(1≤c≤b并且d

c);v,表示债券价值(1≤v≤104)。输入的最后一行,只包含两个用空格分隔的零。输出对于每个测试用例,程序输出一行,包含一个字符:如果可以在没有Nlogonia中央银行救助的情况下清算所有债券,输出“S”;如果需要救助,则输出“N”。试题解析在借贷关系中,将钱借给他人的人;称为债权人;而向别人借钱,欠别人钱的人称为债务人。在输入中的b家银行的货币储备用数组r表示,由于1≤b≤20,银行用从1到b的整数来标识,且银行的货币储备是整数,所以b家银行的货币储备说明为“intr[21];”,且r[i]表示第i家银行的货币储备,1≤i≤20。对于每个测试用例,输入b家银行的货币储备;对于每个d,c,v,d是债务人,欠了c的钱v,所以r[d]-=v;相应地,c是债权人,d要还c钱v,r[c]+=v;在b家银行中,只要有一家银行的货币储备小于0,输出“N”;否则输出“S”。“输入的最后一行,只包含两个用空格分隔的零”,所以,参考程序,每次处理一个测试用例的外层循环以“while(~scanf("%d%d",&b,&n)&&(b||n))”来实现。《程序设计》60【例4.2.4.4】输入n个整数存于数组,对数组作整理,使其中小于0的元素移到前面,等于0的元素留在中间,大于0的元素移到后面程序实例分析引入变量k、h,设在整理过程中,a[0]~a[k-1]都小于0,a[h+1]~a[n-1]都大于0。从a[0]开始顺序考察,设当前正要考察a[j]。则有a[k]至a[j-1]=0,a[j]至a[h]还未考察过。对元素a[j]有下列情况a[j]<0:a[j]与a[k]交换,并且j++和k++;a[j]=0:j++;a[j]>0:a[j]与a[h]交换,并且h--;初始时,j=0,k=0,h=n-1;整理结束后满足:j>h《程序设计》61初始状态:k=j=0;h=n-1《程序设计》62(续)数组整理程序#include<stdio.h>#defineMAXN1000voidmain(){intj,n,k,temp,h,m;inta[MAXN];printf(“Entern\n”);scanf(“%d”,&n);/*输入数组中实际数据*/printf("Entera[0]--a[%d]\n",n-1);for(j=0;j<n;j++)scanf("%d",&a[j]);《程序设计》63(续)数组整理程序j=k=0;h=n-1;while(j<=h)if(a[j]<0){temp=a[j];a[j]=a[k];a[k]=temp;j++;k++;}elseif(a[j]==0)j++;else{temp=a[j];a[j]=a[h];a[h]=temp;h--;}for(j=0;j<n;j++)printf(“%4d”,a[j]);/*输出结果*/printf("\n\n\n");}

《程序设计》64【例4.2.4.5】编一个程序,输入n个互不相等的整数存于数组,并输出。程序如发现输入的数据已输入过,则要求重新输入

#include<stdio.h>#defineMAXN1000voidmain(){inti,n,k;inta[MAXN];printf("Entern");scanf("%d",&n);《程序设计》65(续)输入n个互不相等的整数存于数组,并输出i=0;while(i<n){printf("Entera[%d]",i);scanf("%d",&a[i]);for(k=0;a[k]!=a[i];k++);/*查是否有重复*/if(k<i)/*如果重复*/printf("Error,inputagain!\n");elsei++;/*对于不重复情况*/}for(i=0;i<n;i++)printf("%4d",a[i]);printf("\n\n\n");}《程序设计》66【例4.2.4.6】按递增顺序生成集合M的前n个元素。集合M定义如下整数1属于M如果整数X属于M,则整数2x+1和3x+1也属于M再没有别的整数属于M程序实例分析根据集合M的定义,前几个元素为M={1,3,4,7,9,…}为存储M的元素设计一个足够大的整数组m,用j表示集合M中已生成的元素个数。按题意,首先将1放入集合M中,然后按递增顺序用M中的现有元素枚举出M的新元素《程序设计》68《程序设计》69程序实例分析(续)每个元素可以施行两种枚举方法。在按递增顺序枚举出M的新元素过程中,把M的元素分成以下四部分已执行过2x+1枚举操作的元素已执行过3x+1枚举操作的元素已被枚举生成,但还未执行过任何枚举操作因还未被枚举出来,其值还未定义引进辅助变量e2和e3,分别用于指出m中下一个要执行2x+1枚举的元素的下标和要执行3x+1枚举的元素的下标。为了按递增顺序生成m的元素,下一个可能执行枚举操作的元素是m[e2]和m[e3],选择哪一个由它们枚举出来的值更小来确定另设j为m中已有元素个数《程序设计》70以下代码能描述m在第一次枚举之前的状态

m[0]=j=1;e2=e3=0;而一系列的枚举生成m的n个元素的C代码描述如下

while(j<n){if(m[e3]*3+1>=m[e2]*2+1){/*对m[e2]执行2x+1枚举*/m[j]=m[e2++]*2+1;if(m[e3]*3+1==m[j])e3++;/*当两个元素枚举值相同时,同时枚举*/}elsem[j]=m[e3++]*3+1;j++;}4.2.5冒泡排序排序(sorting)将一个数据元素的任意序列,重新排列成一个按关键字递增或递减的有序序列。冒泡排序重复地对于要排序的元素序列进行遍历,依次比较两个相邻的元素,如果顺序错误,就互换这两个元素。这样的遍历重复进行,直到没有相邻元素需要互换,也就是说该元素序列的排序已经完成。原始序列:2,4,1,3,5;冒泡排序的过程如下:第一轮,对于相邻元素,顺序错误则互换,得序列:2,1,3,4,5;第二轮,得序列:1,2,3,4,5。此时,已经没有相邻元素需要互换,排序完成。用C语言描述上述排序过程for(i=0;i<n-1;i++)/*控制n-1次比较调整遍历*/for(j=0;j<n-1-i;j++)/*第i次遍历需比较n-1-i

次*/if(a[j]>a[j+1]){/*a[j]与a[j+1]交换*/temp=a[j];a[j]=a[j+1];a[j+1]=temp;}【例4.2.5.1】Who'sintheMiddle试题来源:USACO2004November在线测试:POJ2388FJ调查他的奶牛群,他要找到最一般的奶牛,看最一般的奶牛产多少牛奶:一半的奶牛产奶量大于或等于这头奶牛,另一半的奶牛产奶量小于或等于这头奶牛。给出奶牛的数量:奇数N(1≤N<10,000)及其产奶量(1..1,000,000),找出位于产奶量中点的奶牛,要求一半的奶牛产奶量大于或等于这头奶牛,另一半的奶牛产奶量小于或等于这头奶牛。输入第1行:整数N第2行到第N+1行:每行给出一个整数,表示一头奶牛的产奶量。输出一个整数,位于中点的产奶量。提示对于样例输入,5头奶牛,产奶量为1..5;因为1和2低于3,4和5在3之上,所以输出3。试题解析递增排序N头奶牛的产奶量,排序后的中间元素即为位于中点的产奶量。参照冒泡排序C语言程序段,对输入的产奶量序列进行排序,然后输出中点的产奶量。参考程序#include<stdio.h>intmain(){inta[10010],N,i,j,temp;scanf("%d",&N);//输入第1行整数N,N头奶牛for(i=0;i<N;i++)//N头奶牛的产奶量scanf("%d",&a[i]);for(i=0;i<N-1;i++)//冒泡排序N头奶牛产奶量 for(j=0;j<N-i-1;j++) if(a[j]>a[j+1]) {temp=a[j];a[j]=a[j+1];a[j+1]=temp;}printf("%d\n",a[N/2]);//输出排序后的中间元素return0; }《程序设计》81冒泡排序法的改进在冒泡排序过程中,如果某次遍历未发生交换调整情况,这时数组实际上已排好序。程序若发现这种情况后,应提早结束排序过程为此,程序引入一个起标志作用的变量每次遍历前,预置该变量的值为0当发生交换时,置该变量的值为1一次遍历结束时,就检查该变量的值,若其值为1,说明发生过交换,继续下一次遍历;如该变量的值为0,说明未发生过交换,则立即结束排序循环《程序设计》82冒泡排序法的改进(续)引入标志变量flg后相应的排序代码

for(i=0;i<n-1;i++){/*控制n-1次比较调整遍历*/for(flg=j=0;j<n-1-i;j++)/*比较n-1-i次*/if(a[j]>a[j+1]){temp=a[j];a[j]=a[j+1];a[j+1]=temp;flg=1;}if(flg==0)break;}《程序设计》83冒泡排序法的改进(续)更好的改进:在冒泡排序过程中,若某次遍历在某个位置j发生最后一次交换,j以后的位置都未发生交换,则实际上j以后位置的全部元素都是已排好序的利用这个性质,后一次遍历的范围可立即缩短至上一次遍历的最后交换处程序为利用这个性质,引入每次遍历的上界变量end,另引入变量k记录每次遍历的最后交换位置为了考虑到可能某次遍历时一次也不发生交换的情况,在每次遍历前时,预置变量k为0。一次遍历结束后,将k赋给end,作为下一次遍历的上界。冒泡排序过程至end为0结束,end的初值为n-1,表示第一次遍历至最后一个元素《程序设计》84冒泡排序法的改进(续)更好的改进:按上述想法把冒泡排序代码改进如下

end=n-1;/*end用于记录本次遍历范围的上界*/while(end>0){/*扫视范围非空时循环*/for(k=j=0;j<end;j++)/*比较至end*/ if(a[j]>a[j+1]){temp=a[j];a[j]=a[j+1];a[j+1]=temp;k=j;/*记录发生交换的位置*/}end=k;}《程序设计》854.3.1多维数组定义、引用和存放特点4.3.2多维数组初始化4.3.3多维数组程序示例4.3多维数组《程序设计》864.3.1多维数组定义、引用和存放特点二维数组a[4][6]三维数组a[5][4][6]行下标

i;列下标

j页下标

i;行下标

j;列下标k《程序设计》87多维数组定义二维数组的定义形式为类型说明符数组名[常量表达式][常量表达式];多维数组示例floata[2][3],b[3][4];

/*两个二维数组*/floatc[2][2][3];

/*一个三维数组*/二维数组的元素的存放顺序是按行存放,即从数组首地址开始,先顺序存放第一行元素,再存放第二行元素例如,对于上面数组a[2][3],其元素在内存中的存放顺序为:a[0][0]、a[0][1]、a[0][2]、a[1][0]、a[1][1]、a[1][2]《程序设计》88floata[2][3];float型二维数组,数组名为a,数组第一维有2个元素,数组第二维有3个元素;可以把二维数组a看作一个一维数组,它有2个元素:a[0]和a[1],每个元素又是一个包含3个元素的一维数组。多维数组引用引用二维数组元素:数组名[下标][下标];其中,“下标”可以是整型常量或整型表达式。二维数组a[4][6],引用数组元素a[2][2]=a[1][1]+2。在用下标引用数组的元素时,应该注意下标值的有效性,应在已定义的对应维大小的范围内,即大于等于0,和小于对应维的元素个数。二维数组a[4][6],引用数组元素a[i][j],0

i<4,0

j<6。《程序设计》90多维数组存放特点一个多维数组的元素在内存中的存放顺序有这样的特点:第一维的下标变化最慢,最右边的下标变化最快例如,对于前面例子中的三维数组c[2][2][3],其元素的存放顺序为c[0][0][0]、c[0][0][1]、c[0][0][2]、c[0][1][0]、c[0][1][1]、c[0][1][2]、c[1][0][0]、c[1][0][1]、c[1][0][2]、c[1][1][0]、c[1][1][1]、c[1][1][2]。《程序设计》-2008年秋914.3.2多维数组初始化按行给二维数组的全部元素赋初值

inta1[2][3]={{1,2,3},{4,5,6}};按元素存储顺序给数组元素赋初值

inta2[2][3]={1,2,3,4,5,6};按行给数组的部分元素赋初值

inta3[2][3]={{1,2},{0,5}};/*其余均为0*/inta4[3][4]={{1},{0,6},{0,0,1}};inta5[3][4]={{1},{5,6}};inta6[3][4]={{1},{},{9}};《程序设计》-2008年秋92多维数组初始化(续)按元素存储顺序给前面部分元素赋初值

inta4[2][3]={1,2,3,4};/*其余均为0*/按元素存储顺序,给数组部分或全部元素赋初值,并且不指定第一维的元素个数

inta5[][3]={1,2,3,4,5};/*两行*/用按行赋初值方法,对各行的部分或全部元素赋初值,并省略第一维的元素个数

inta6[][3]={{0,2},{}};/*两行*/《程序设计》-2008年秋934.3.3多维数组程序示例二维数组元素按行输入和按行输出示意程序

#include<stdio.h>voidmain(){inta[2][3],i,j;for(i=0;i<2;i++)/*二维数组元素按行输入*/for(j=0;j<3;j++){printf("Entera[%d][%d]",i,j);scanf("%d",&a[i][j]);}for(i=0;i<2;i++){/*二维数组元素按行输出*/for(j=0;j<3;j++)printf("%d\t",a[i][j]);printf("\n");/*按行换行*/}}《程序设计》94【例4.3.3.1】有一个3×4的矩阵,求出其中值最大的那个元素及其所在的行号和列号《程序设计》95#include<stdio.h>voidmain(){inti,j,row=0,colum=0,max;inta[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;colum=j;}

printf("max=%d,row=%d,colum=%d\n",max,row,colum);}

输出结果为:max=10,row=2,colum=1【例4.3.3.2】PascalLibrary试题来源:ACMSouthAmerica2005在线测试:POJ2864,UVA3470Pascal大学是国家最古老的大学之一。Pascal大学要翻新图书馆大楼,因为经历了几个世纪后,图书馆开始出现无法承受馆藏的巨大数量的书籍的重量的迹象。为了帮助重建,大学校友会决定举办一系列的筹款晚宴,邀请所有的校友参加。在过去几年举办了几次筹款晚宴,这样的做法已经被证明是非常成功的。成功的原因之一是经过Pascal教育体系的学生对他们的学生时代有着美好的回忆,并希望看到一个重修后的Pascal图书馆。组织者保留了电子表格,表明每一场晚宴有哪些校友参加了。现在,他们希望您帮助他们确定是否有校友参加了所有的晚宴。输入输入包含若干测试用例。一个测试用例的第一行给出两个整数n和d,分别给出校友的数目和组织晚宴的场数(1≤n≤100,并且1≤d≤500)。校友编号从1到n。后面的d行每行表示一场晚宴的参加情况,给出n个整数xi,如果校友i参加了晚宴,则xi

=1,否则xi

=0。用n=d=0作为输入结束。输出对于输入中的每个测试用例,你的程序产生一行,如果至少有一个校友参加了所有的晚宴,则输出“yes”,否则输出“no”。试题解析校友的出席筹款晚宴的情况用二维数组att表示:att[i][j]表示在第i-1场筹款晚宴上第j-1个校友是否出席,att[i][j]=1表示出席,att[i][j]=0表示没有出席;在输入时对att进行赋值。对每个校友出席筹款晚宴的场数进行计算,设flag为校友出席筹款晚宴的场数。如果有校友参加了所有的晚宴,则输出“yes”;否则输出“no”。【例4.3.3.3】EventPlanning试题来源:Onemorehighlevelcontest,2009在线测试:UVA11559尽管您没有出席NordicClubofPinCollectors的年度会员大会,你还是被一致推选组织今年的PinCity观光旅行。今年秋天,你要为大家选择一个周末,并且要找一家合适的酒店住宿,最好尽可能便宜。您会有一些限制:旅行的总费用必须在预算范围内,所有参加者都必须住在同一家酒店。输入输入包含若干测试用例,每个测试用例如下所述。第一行输入给出四个整数:1≤N≤200,参与者人数;1≤B≤500000,预算;1≤H≤18,需要考虑的酒店数量;1≤W≤13,您可以选择的周末数。接下来,然后,H家酒店,每家酒店两行信息:第一行给出1≤p≤10000,即一个人在这家酒店住一个周末的价格;第二行给出W个整数,0≤a≤1000,表示这家酒店在每个周末可以提供的床位数量。输出对于每个测试用例,输出一行,给出最低的预算,如果最低预算超过给定预算值,则输出“stayhome”。试题解析处理的数据H家酒店,用一维整数数组p[18]表示周末单价;H家酒店W个周末,用二维整数数组a[18][13]表示每个周末每家酒店的床位数。每次循环处理一个测试用例。对于每个测试用例,外层循环,每次循环处理一个周末;内层循环,每次循环处理一家酒店,循环体内判断:这家酒店在这个周末是否有足够的床位(a[i][j]>=n),并且费用是否小于当前的最低预算(p[i]*n<minb),如果是,则调整最低预算为当前费用(minb=p[i]*n)。最后,输出结果。《程序设计》106多维数组程序示例-2把某月的第几天转换成年的第几天程序实例分析为确定一年中的第几天,需要一张每月的天数表,该表给出每个月份的天数。由于二月份天数因闰年和非闰年有所不同,为程序处理方便,把月份天数表组织成一个二维数组《程序设计》-2008年秋107多维数组程序示例-2(续)(续)把某月的第几天转换成年的第几天

#include<stdio.h>intday_table[][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};voidmain(){intyear,month,day,leap,i;printf("Inputyear,month,day.\n");scanf("%d%d%d",&year,&month,&day);

leap=year%4==0&&year%100||year%400==0;for(i=0;i<month-1;i++)day+=day_table[leap][i];printf("\nThedaysinyearis%d.\n",day);}《程序设计》108多维数组程序示例-3已知年份与年中的第几天,计算该天是这年的哪一月和哪一日

#include<stdio.h>intday_table[][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};charmonthname[][10]={"January","February","March","April","May","June","July","August","September","Octorber","November","December"};《程序设计》109多维数组程序示例-3(续)(续)已知年份与年中的第几天,计算该天是这年的哪一月和哪一日

voidmain(){intyear,day,leap,i;printf("Inputyear,dayofyear.\n");scanf("%d%d",&year,&day);leap=year%4==0&&year%100||year%400==0;for(i=0;day>day_table[leap][i];i++)day-=day_table[leap][i];printf("Themonthis%s,theDayis%d.\n",monthname[i],day);}《程序设计》110多维数组程序示例-4输入整数n,输出以下形式的二维数组

123...nn12...n-1n-1n1...n-2...234...1注:上面问题有多种解法《程序设计》111多维数组程序示例-4(续)解法1:先给出第0行,然后利用i行与i-1行的关系,求出i行

for(j=0;j<n;j++)/*先形成第0行*/a[0][j]=j+1;for(i=1;i<n;i++){a[i][0]=a[i-1][n-1];/*生成i行的第0列*/ for(j=1;j<n;j++)/*生成i行的其余列*/ a[i][j]=a[i-1][j-1];}《程序设计》112多维数组程序示例-4(续)解法2:将i行的内容分成两部分i行内容:n-i+1...n1...n-ifor(i=0;i<n;i++){k=1; for(j=i;j<n;j++)/*右上部分*/ a[i][j]=k++; for(j=0;j<i;j++)/*左下部分*/ a[i][j]=k++;}《程序设计》113多维数组程序示例-4(续)解法3:将方法2中的变量k去掉,直接代入算式

for(i=0;i<n;i++){for(j=i;j<n;j++)a[i][j]=j-i+1;for(j=0;j<i;j++)a[i][j]=j-i+1+n;}解法4:将方法3中的两个j循环合并

for(i=0;i<n;i++)for(j=0;j<n;j++)a[i][j]=j<i?j-i+1+n:j-i+1;《程序设计》114多维数组程序示例-4(续)解法5:将4中的条件表达式简化

for(i=0;i<n;i++)for(j=0;j<n;j++)a[i][j]=(j-i+n)%n+1;解法6:先给出第0行,再由i行与0行的关系求出i行

for(j=0;j<n;j++)a[0][j]=j+1;for(i=1;i<n;i++)for(j=0;j<n;j++)a[i][j]=a[0][(j-i+n)%n];《程序设计》115多维数组程序示例-4(续)解法7:对i行,从i列开始,从顺将整数填入到数组中

for(i=0;i<n;i++)for(j=i;j<i+n;j++)/*i行从j列开始填n次*/a[i][j%n]=j-i+1;还有许多填值的方法,请大家自已再想出方法,并写出C实现代码《程序设计》116多维数组程序示例-5形成以下形式的二维数组(以n=4为例),并输出

11192024251012182123491317223581416126715程序实例分析n*n的二维数组,共有2n-1条斜线,将它们顺次编号为1至2*n-1第奇数条斜线从左上往右下;第偶数条斜线从右下往左上《程序设计》117多维数组程序示例-5(续)程序实例分析(续)程序按从左下角至右上角的顺序逐条斜线填数。斜线的填数方向按斜线的奇偶性交替变化每条斜线的行列起始位置的变化规律与斜线位于下三角或上三角有不同对于下三角,第奇数条斜线从左上往右下,起始行号为n-d(d为斜线编号,下同),起始列号为0;第偶数条斜线从右下往左上,起始行号为n-1,起始列号为d-1对于上三角,第奇数条斜线从上往下,起始行号为0,起始列号为d-n;第偶数条斜线从下往上,起始行号为2*n-1-d,起始列号为n-1《程序设计》118多维数组程序示例-5(续)按以上情况分类,写出程序如下

#include<stdio.h>#defineMAXN10inta[MAXN][MAXN];voidmain(){inti,j,k,d,n;while(1){/*n不超过10*/printf("Entern");scanf("%d",&n);

if(n>=1&&n<=10)break;printf("Error!nmustbein[1,10]\n");}《程序设计》119多维数组程序示例-5(续)程序(续)

for(k=d=1;d<=2*n-1;d++){if(d<=n-1)/*左下三角*/ if(d%2)/*奇数号斜线,从左上往右下*/for(i=n-d,j=0;i<n;i++,j++) a[i][j]=k++; else/*偶数号斜线,从右下往左上*/for(i=n-1,j=d-1;i>=n-d;i--,j--)a[i][j]=k++;《程序设计》120多维数组程序示例-5(续)程序(续)

else/*d>=n,右上三角*/if(d%2)for(i=0,j=d-n;i<=2*n-1-d;i++,j++)a[i][j]=k++;elsefor(i=2*n-1-d,j=n-1;i>=0;i--,j--)a[i][j]=k++;}for(i=0;i<n;i++){for(j=0;j<n;j++)printf("%4d",a[i][j]);printf("\n");}}4.4字符串处理技术基础字符和对应的ASCII码是等价的字符串(String)是由零个或多个字符组成的有限序列。一般记为

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论