收藏 分享(赏)

第三章2 算法与数据结构.ppt

上传人:Facebook 文档编号:3491512 上传时间:2018-11-05 格式:PPT 页数:55 大小:214.50KB
下载 相关 举报
第三章2 算法与数据结构.ppt_第1页
第1页 / 共55页
第三章2 算法与数据结构.ppt_第2页
第2页 / 共55页
第三章2 算法与数据结构.ppt_第3页
第3页 / 共55页
第三章2 算法与数据结构.ppt_第4页
第4页 / 共55页
第三章2 算法与数据结构.ppt_第5页
第5页 / 共55页
点击查看更多>>
资源描述

1、32 算法与数据结构,321 原始信息与处理结果的对应存储 322 数组使信息有序化 323 数组记录状态信息 324 大整数存储及运算 325 构造趣味矩阵,计算机处理问题的类型可分为:数值计算问题和非数值性问题,存储结构可以分为:连续存储和链式存储。连续存储又可以分为:静态存储和动态存储,1、常用的几种数据结构,顺序存储的优点:(1) 方法简单,各种高级语言中都提供数组结构,容易实现。(2) 不用为表示结点间的逻辑关系而增加额外的存储开销。(3) 顺序表具有按元素序号随机访问的特点。,2、连续存储和链式存储比较,顺序存储的缺点:(1) 在顺序表中做插入删除操作时,平均移动大约表中一半的元素

2、,因此对n较大的顺序表效率低。(2) 需要预先分配足够大的存储空间,估计过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出。,链表的优缺点恰好与顺序表相反。,3、在选取存储结构时权衡因素有:,)基于存储的考虑 顺序表的存储空间是静态分配的,在程序执行之前必须明确规定它的存储规模,过大造成浪费,过小造成溢出。 对线性表的长度或存储规模难以估计时,不宜采用顺序表; 链表不用事先估计存储规模,但链表的存储密度较低,,)基于运算的考虑 如果经常做的运算是按序号访问数据元素,顺序表优于链表; )基于环境的考虑 顺序表容易实现,任何高级语言中都有数组类型,链表的操作是基于指针的,操作简单。,3

3、21 原始信息与处理结果对应存储,在算法中一般有输入信息、输出信息和信息加工处理过程中的中间信息。那么哪些信息需要用数组进行存储,数组元素下标与信息怎么样对应等问题的确定,在很大程度上影响着算法的编写效率和运行效率。 【例1】统计选票 【例2】统计身高 【例3】统计及格学生的名单 【例4】统计找数字对的出现频率,【例1】某次选举,要从五个候选人(编号分别为1、2、3、4、5)中选一名厂长。请编程完成统计选票的工作。 算法设计:,1)虽然选票发放的数量一般是已知的,但收回的数量通常是无法预知的,所以算法采用随机循环,设计停止标志为“-1”。 2)统计过程的一般方法为: 先为五个候选人各自设置五个

4、“计数器”S1,S2,S3,S4,S5, 根据录入数据通过多分支语句或嵌套条件语句决定为某个“计数器”累加1, 这样做效率太低,把五个“计数器”用数组代替,选票中候选人的编号xp正好做下标,执行A(xp)=A(xp)+1就可方便地将选票内容累加到相应的“计数器”中。也就是说数组结构是存储统计结果的,而其下标正是原始信息。3)考虑到算法的健壮性,要排除对15之外的数据进行统计。,vote( ) int i,xp,a6; print(“input data until input -1”); input(xp );while(xp!=-1)if (xp=1 and xp=5 )axp=axp+1;

5、elseprint(xp, “input error!“); input(xp );for (i=1;i=5;i+)print(i,“number get“, ai, “votes“); ,【例2】编程统计身高(单位为厘米)。统计分150154;155159;160164;165169;170174;175179及低于是150、高于是179共八档次进行。,算法设计: 输入的身高可能在50250之间,若用输入的身高数据直接作为数组下标进行统计,即使是用PASCAL语言可设置上、下标的下界,也要开辟200多个空间,而统计是分八个档次进行的,这样是完全没有必要的。 由于多数统计区间的大小是都固定为5

6、,这样用“身高5-29”做下标,则只需开辟8个元素的数组,对应八个统计档次,即可完成统计工作。,main( ) int i,xp,a8; print(“input height data until input -1”); input(sg );while (sg-1)if (sg179) a7=a7+1;else if (sg150) a0=a0+1;else asg5-29=asg5-29+1;input( sg );for (i=0;i=7;i=i+1)print(i+1 ,“field the number of people: ”,ai); ,【例3】一次考试共考了语文、代数和外语三

7、科。某小组共有九人,考后各科及格名单如下表,请编写算法找出三科全及格的学生的名单(学号)。,方法一:,从语文及格名单中逐一抽出各及格学生学号,先在代数及格名单核对,若有该学号(说明代数也及格了),再在外语及格名单中继续查找,看该学号是否也在外语及格名单中。若仍在,说明该号属全及格学生的学号,否则就是至少有一科不及格的。若语文及格名单中就没有某生的号,显然该生根本不在比较之列,自然不属全及格学生 。,该方法采用了枚举尝试的方法 A,B,C三组分别存放语文、代数、外语及格名单,尝试范围为三重循环:I循环, 初值0, 终值6, 步长1J循环, 初值0, 终值5, 步长1K循环, 初值0, 终值7,

8、步长1 定解条件:AI=BJ=CK 共尝试7*6*8=336次。,方法一算法如下:,main( ) int a7, b6, c8,i,j,k,v,flag;for( i =0;i=6;i=i+1) input(ai);for( i =0;i=5;i=i+1) input(bi);for( i =0;i=7;i=i+1) input(ci);for( i =0;i=6;i=i+1)v=ai;for( j =0;j=5;j=j+1)if ( bj=v ) for(k =0;k=7;k=k+1)if(ck=v) print(v); break; ,方法二 :,用数组A的九个下标分量作为各号考生及格科

9、目的计数器。将三科及格名单共存一个数组,当扫描完毕总及格名单后,凡下标计数器的值为3的就是全及格的,算法步骤为: 1)用下标计数器累加各学号学生及格科数, 2)尝试、输出部分。 累加部分为一重循环,初值1 ,终值为三科及格的总人数,包括重复部分。计7+6+8=21,步长1。 尝试部分:寻找三科及格的人.一重循环,初值1 ,终值9,步长1。 定解条件:A(i)=3,方法二算法如下:,main( ) int a10,i,xh; for(i =1;i=21;i=i+1)input(xh);axh=axh+1; for(xh =1;xh=9;xh=xh+1)if(axh =3 )print(xh);

10、,【例4】统计找数字对的出现频率,算法说明: 输入N(2N100)个数字(在0与9之间),然后统计出这组数中相邻两数字组成的链环数字对出现的次数。例如: 输入:N=20 0 1 5 9 8 7 2 2 2 3 2 7 8 7 8 7 9 6 5 9 输出:(7,8)=2 (8,7)=3 指(7,8)、(8,7)数字对出现次数分别为2次、3次(7,2)=1 (2,7)=1(2,2)=2(2,3)=1 (3,2)=1,算法设计: 其实并不是只有一维数组这样的数据结构可以在算法设计中有多采的应用,根据数据信息的特点,二维数组的使用同样可以使算法易于实现,此题就正是如此。 用10*10的二维数组(行、

11、列下标均为0-9),存储统计结果,i行j列存储数字对(i,j)出现的次数,无需存储原始数据,用其做下标,在数据输入的同时就能统计出问题的结果,,算法如下:,main( ) int a1010,m,i,j,k1,k0; print(“How many is numbers?”);input(n); print(“Please input these numbers:”); input(k0);for (i=2;i0 and aji0); print(“(”,i,j,”)=“,aij,”,(”,j,i,”)=”,aji) ,322数组使信息有序化,当题目中的数据缺乏规律时,很难把重复的工作抽象成循

12、环不变式来完成,但先用数组结构存储这些地信息后,问题就迎刃而解了,,【例1】编程将编号“翻译”成英文。例35706“翻译”成three-five-seven-zero-six。,例1 例2,算法设计1:,算法设计1:1) 编号一般位数较多,可按长整型输入和存储。2) 将英文的“zeronine”存储在数组中,对应下标为09。这样无数值规律可循的单词,通过下标就可以方便存取、访问了。3) 通过求余、取整运算,可以取到编号的各个位数字。用这个数字作下标,正好能找到对应的英文数字。4)翻译结果是从高位到低位进行的,所以还要开辟一个数组来存储从低位到高位翻译好的结果,最后倒着从高位到低位输出结果。,算

13、法如下:,main( )int i,a10, ind; long num1,num2;char eng106=“zero”,”one”,”two”,”three ”,” four”,” five”,”six”,”seven”,“eight”,”nine”;print(“Input a num”);input(num1); num2=num1; ind =0; while (num20) aind=num2 mod 10; ind= ind +1; num2=num2/10; print(num1, “English_exp:”, engaind-1);for( i=ind-2;i=0;i=i-

14、1)print(“-”,engai); ,【例2】一个顾客买了价值x元的商品,并将y元的钱交给售货员。售货员希望用张数最少的钱币找给顾客。,问题分析:无论买商品的价值x是多大,找给他的钱最多需要以下六种币值:50,20,10,5,2,1。,算法设计:1)为了能达到找给顾客钱的张数最少,先尽量多地取大面额的币种,由大面额到小面额币种逐渐进行。2)六种面额不是等到差数列,为了能构造出循环不变式,将六种币值存储在数组B。这样,六种币值就可表示为Bi,i=1,2,3,4,5,6。为了能达到先尽量多地找大面额的币种,六种币值应该由大到小存储。3)另外还要为统计六种面额的数量,同样为了能构造出循环不变式,

15、设置一个有六个元素的累加器数组S,这样操作就可以通过循环顺利完成了。,算法如下:,main( ) int i,j,x,y,z,a,b7=0,50,20,10,5,2,1,s7;/累加数组 input(x,y); z=y-x; for(i=1;i0)print(bi, “-”, si); ,/每求出一种面额所需的张数后,一定要把这部分金额减去: “y=y-A*Bj;”,否则将会重复计算。,算法分析:问题的规模是常量,时间复杂性肯定为O(1)。,323 数组记录状态信息,问题提出:有的问题会限定在现有数据中每个数据只能被使用一次,怎么样表示一个数据“使用过”还是没有“使用过”?一般想法是:用数组存

16、储已使用过的数据,然后每处理一个新数据就与前面的数据逐一比较看是否重复。这样做,当数据量大时,判断工作的效率就会越来越低。,开辟状态数组,专门记录数据使用情况,将信息与下标对应,例1,【例1】求X,使X2为一个各位数字互不相同的九位数。算法分析:只能用枚举法尝试完成此题。由X2为一个九位数,估算X应在1000032000之间。,算法设计:1) 用一个10 个元素的状态数组p,记录数字09在X2中出现的情况。数组元素都赋初值为1,表示数字09没有被使用过。2) 对尝试的每一个数x,求x*x,并取其各个位数字,数字作为数组的下标,若对应元素为1,则该数字第一次出现,将对应的元素赋为0,表示该数字已

17、出现一次。否则,若对应元素为0,则说明有重复数字,结束这次尝试。3) 状态数组p中有9个元素为0时,就找到了问题的解。4) 但这样需要扫描一遍数组p。为避免这个步骤,设置一个计数器k,在取x*x各个位数字的过程中记录不同的数字的个数,当k=9时就找到了问题的解。,main( ) long x, y1, y2; int p10, i, t, k, num=0;for (x=10000;x32000; x=x+1) for(i=0; i=9; i=i+1) pi=1;y1=x*x ;y2=y1; k=0;for(i=1; i=9; i=i+1)t=y2 mod 10; y2=y210;if(pt=

18、1)k=k+1; pt=0;else break;if(k=9)num=num+1; print (“No.”,num , “:n=”, x, “n2=”, y1); ,main( ) long x, y1, y2; int p10, i, t, k, num=0; outer: for (x=10000;x32000; x=x+1) for(i=0; i=9; i=i+1) pi=1;y1=x*x ;y2=y1; k=0;for(i=1; i=9; i=i+1)t=y2 mod 10; y2=y210;if(pt=1)k=k+1; pt=0;else continue outer;print

19、 (“No.”,num , “:n=”, x, “n2=”, y1); ,12个小朋友手拉手站成一个圆圈,从某一个小朋友开始报数,报到7的那个小朋友退到圈外,然后他的下一位重新报“1”。这样继续下去,直到最后只剩下一个小朋友,求解这个小朋友原来站在什么位置上呢?,【例2】游戏问题:,算法设计:,如何表示状态的问题:开辟12个元素的数组,记录12个小朋友的状态,开始时将12个元素的数组值均赋为1,表示大家都在圈内。如何表示报数就用累加数组元素的值来模拟,累加到7时,该元素所代表的小朋友退到圈外,将相应元素的值改赋为0,这样再累加到该元素时和不会改变,又模拟了已出圈外的状态。,算法如下:,main

20、( ) int a100,i,k,p,m;print(“input numbers of game:”);input(n); print(“input serial number of game start:”);input(k); print(“input number of out_ring:”);input(m);for( i=1;i=n;i+)ai=1; p=0;,n表示做游戏的总人数 k表示开始及状态数组的下标变量 m表示退出圈外的报数点,即报m的人出队 p表示已退出圈外的人数。,while (pn) k=1;x=x+ak;print(k);ak=0;p=p+1; for( i=1;

21、i=n;i+)if ( ai=1)print( “i=”,i); ,/循环条件:剩下一人,/条件:报m的人出列,/算法中当某人编号k n时,赋k=1,表示n号即最后一个人报号完毕后就该1号报数。模拟了将n个人连成了一个“圈”的情况,/每次向后移动一个人报数,/将数组数值相加,当x=m,则表示编号为k的人出列,/以下表示有编号K的人出列,将数值置为0,出列人数P加1,/输出最后数值为1仍在圈内的人,324 大整数的存储及运算,计算机存储数据是按类型分配空间的。 在微型机上为整型提供2个字节16位的存储空间,则整型数据的范围为-3276832767; 为长整型提供4个字节32位的存储空间,则长整型

22、数据的范围为-21474836482147483647; 为实型也是提供4个字节32位的存储空间,但不是精确存储数据,只有六位精度,数据的范围(3.4e-383.4e+38) ; 为双精度型数据提供8个字节64位的存储空间,数据的范围(1.7e-3081.7e+308),其精确位数是17位。,返回3.2.4,只有大型科研机构才有可能拥有更高精度数值类型,当我们需要在个人机上,对超过长整型的多位数(简称为“高精度数据”)操作时,只能借助于数组才能精确存储、计算。,在用数组存储高精度数据时,从计算的方便性考虑,决定将数据是由低到高还是由高到低存储到数组中;可以每位占一个数组元素空间,也可几位占一个

23、数组元素空间。,【例】编程求当N=100时,N!的准确值 问题分析:问题要求对输入的正整数N,计算N!的准确值,而N!的增长速度仅次于指数增长的速度,所以这是一个高精度计算问题。 例如: 9!=362880 100! = 93 326215 443944 152681 699263 856266 700490 715968 264381 621468 592963 895217 599993 229915 608914 463976 156578 286253 697920 827223 758251 185210 916864 000000 000000 000000 000000,返回3.

24、2.4,算法设计:,1)乘法的结果是按由低位到高位存储在数组a中 2)由于计算结果位数太多,若每个存储空间只存储一位数字,对每一位进行累乘次数太多。所以将数组定义为长整型,每个元素存储六位。 3)用二重循环来实现两个高精度数据的乘法运算。 其中 循环变量i代表累乘的数据, b存储计算的中间结果, d存储超过六位数后的进位。 数组a存储每次累乘的结果,每个元素存储六位数据,,b=aj*i+d,d=b1000000,aj=b%1000000,算法如下:,main( ) long a256,b,d; int m,n,i,j,r; input(n); m=log(n)*n/6+2; a1=1; for

25、( i=2; i=m;i+)ai=0; d=0; for( i=2; i=n;i+)for (j=1;j=m;j+)b=aj*i+d; aj=b%1000000; d=b/1000000;,返回3.2.4,If(d0)aj=d; for (i=m ;i=1;i-)if( ai=0) continue; elser=i;break;,print(n,“!=”); print(ar);for(i=r-1;i=1;i-)if (ai99999) print(ai); continue;if (ai9999) print( “0”,ai); continue;if (ai 999) print( “0

26、0”,ai); continue;if (ai99 ) print( “000”,ai); continue;if (ai9) print( “0000”,ai); continue;print( “00000”,ai);/for ,返回3.2.4,算法说明:,1)算法中“m=log(n)*n/6+2;”是对N!位数的粗略估计。 可换为:m=1;if(d0) aj=d;m=m+1;,325 构造趣味矩阵,趣味矩阵 经常用二维数组来解决,根据趣味矩阵中的数据规律,设计算法把要输出的数据存储到一个二维数组中,最后按行输出该数组中的元素。,基本常识: 1)当对二维表按行进行操作时,应该“外层循环控制

27、行;内层循环控制列”;反之若要对二维表按列进行操作时,应该“外层循环控制列;内层循环控制行”。 2)二维表和二维数组的显示输出,只能按行从上到下连续进行,每行各列则只能从左到右连续输出。所以,只能用“外层循环控制行;内层循环控制列”。,返回3.2.5 例1 例2 例3,0 1 1 1 0 2 0 1 0 4 2 2 0 4 4 2 0 3 0 4 0 3 3 3 0,2,3)用i代表行下标,以j代表列下标(除特别声明以后都遵守此约定),则对n*n矩阵有以下常识: 主对角线()元素i=j; 副对角线(/)元素: 下标下界为1时 i+j=n+1,下标下界为0时i+j=n-1; 主上三角元素: i

28、=j; 次上三角元素:下标下界为1时i +j=n+1,下标下界为0时i+j=n-1;,返回3.2.5 例1 例2 例3,【例1】编程打印形如下规律的n*n方阵。,例如下图:使左对角线和右对角线上的元素为0,它们上方的元素为1,左方的元素为2,下方元素为3,右方元素为4,下图是一个符合条件的阶矩阵。 0 1 1 1 0 2 0 1 0 4 2 2 0 4 4 2 0 3 0 4 0 3 3 3 0,算法设计:根据数据分布的特点,利用以上关于二维数组的基本常识 0:主对角线和次对角线 i=j or i+j=n+1 1:主上三角并次上三角 ij and i+jj and i+jn+1 4:主上三角并

29、次下三角 in+1,算法如下: main( ) int i,j,a100100,n;input(n);for(i=1;ij) a ij=2;if (i+jn+1 and ij) a ij=3;if (i+jn+1 and ij) a ij=4; for(i=1;i=n;i=i+1)print( “换行符”); for( j=1;j=n;j=j+1)print(aij); ,返回3.2.5 例1 例2 例3,n=3 输出: 1 8 72 9 63 4 5 n=4 输出: 1 12 11 102 13 16 93 14 15 84 5 6 7,【例2】螺旋阵:任意给定n值,按如下螺旋的方式输出方阵

30、:,返回3.2.5 例1 例2 例3,算法设计:,算法设计1:此例可以按照“摆放”数据的过程,逐层(圈)分别处理每圈的左侧、下方、右侧、上方的数据。以n=4为例详细设计如下:把“112”看做一层(一圈)“13-16”看做二层以层做为外层循环,下标变量为i。由以上两个例子,n=3、4均为两层,用n2表示下取整,这样(n+1)/2下好表示对n/2上取整。所以下标变量i的范围1(n+1)/2。,返回3.2.5 例1 例2 例3,i层内“摆放”数据的四个过程为(四角元素分别归四个边): 1) i列(左侧),从i行到n-i行 ( n=4,i=1时 “摆放1,2,3”) 2) n+1-i行(下方),从i列

31、到n-i列 ( n=4,i=1时 “摆放4,5,6”) 3) n+1-i列(右侧),从n+1-i行到i+1行 ( n=4,i=1时 “摆放7,8,9”) 4) i行(上方),从n+1-i列到i+1列 ( n=4,i=1时 “摆放10,11,12”) 四个过程通过四个循环实现,用j表示i层内每边中行或列的下标。,返回3.2.5 例1 例2 例3,main( ) int i,j,a100100,n,k;input(n); k=1; for(i=1;i=i+1;j=j-1)ajn+1-i=k;k=k+1; /右侧/for( j= n-i+1;j=i+1;j=j-1) aij=k; k=k+1; /上

32、方/ if (n mod 2=1)i=(n+1)/2; aii=n*n; for(i=1;i=n;i=i+1)print(“换行符”); for( j=1;j=n;j=j+1)print(aij); ,返回3.2.5 例1 例2 例3,魔方阵是我国古代发明的一种数字游戏:n阶魔方是指这样一种方阵,它的每一行、每一列以及对角线上的各数之和为一个常数,这个常数是:n*(n2+1)/2,此常数被称为魔方阵常数。由于偶次阶魔方阵(n=偶数)求解起来比较困难,我们这里只考虑n为奇数的情况。 以下就是一个n=3的魔方阵:6 1 87 5 32 9 4 它的各行、各列及对角线上的元素之和为15。,【例3】设

33、计算法生成魔方阵,返回3.2.5 例1 例2 例3,算法设计:有趣的是如果我们将1,2,n2按某种规则依次填入到方阵中,得到的恰好是奇次魔方阵,这个规则可以描述如下: (1)首先将1填在方阵第一行的中间,即(1,(n+1)/2)的位置; (2)下一个数填在上一个数的主对角线的上方,若上一个数的位置是(i,j),下一个数应填在(i1,j1),其中i1=i-1、j1=j-1。 (3)若应填写的位置下标出界,则出界的值用n 来替代;即若i-1=0,则取i1=n;若j-1=0,则取j1=n。 (4)若应填的位置虽然没有出界,但是已经填有数据的话,则应填在上一个数的下面(行加1,列不变),即取i1=i+

34、1,j1=j。 这样循环填数,直到把n*n个数全部填入方阵中,最后得到的是一个n阶魔方阵。,main( ) int i,j, i1,j1,x,n,t,a100100; print(“input an odd number:”); input(n); if (n mod 2=0) print(“input error!”); return; for( i=1;i0 ) i=i1+1; j=j1; ,for( i=1;i=n;i=i+1)print(“换行符”);for(j=1;j=n;j=j+1)print(aij); ,算法说明:若当前位置已经填有数的话,则应填在上一个数的下面,所以需要用变量记录上一个数据填入的位置,算法中i1,j1的功能就是记录上一个数据填入的位置。 算法分析:算法的时间复杂度为O(n2)。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 中等教育 > 小学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报