550 likes | 698 Views
作业选讲. 给一维数组输入任意 6 个整数 , 假设为 : 7 4 8 9 1 5 请建立一个具有以下内容的方阵: 7 4 8 9 1 5 4 8 9 1 5 7 8 9 1 5 7 4 9 1 5 7 4 8 1 5 7 4 8 9 5 7 4 8 9 1 ( 请用子程序编写 ) 。. 赵自为. program zzw; const s :array[1..6] of integer=(1,2,3,4,5,6); var q:integer; procedure hhh ; var t,j:integer;
E N D
给一维数组输入任意6个整数,假设为: 7 4 8 9 1 5 请建立一个具有以下内容的方阵: 7 4 8 9 1 5 4 8 9 1 5 7 8 9 1 5 7 4 9 1 5 7 4 8 1 5 7 4 8 9 5 7 4 8 9 1 (请用子程序编写)。
赵自为 program zzw; const s:array[1..6] of integer=(1,2,3,4,5,6); var q:integer; procedure hhh; var t,j:integer; beginj:=s[1];for t:=1 to 5 dos[t]:=s[t+1];s[6]:=j; for t:=1 to 6 do write(s[t],' ');writeln; end; Begin for q:=1 to 6 do write(s[q],' '); writeln; for q:=1 to 5 do hhh;end.
输入n个正整数 求它们的最大公约数。。。(n=5) 让程序更有通用性, program zzw; const n=5; var s:array[1..n] of integer; g,t:integer; function gys(x,y:integer):integer; var z:integer; begin repeat z:=x mod y; x:=y; y:=z; until z=0; gys:=x; end; begin for t:=1 to n do read(s[t]); g:=s[1]; for t:=2 to n do g:=gys(g,s[t]); writeln('the gys is ',g); end.
var m,n:longint ; function gcd(m,n:longint):longint; begin if m mod n=0 then gcd :=n else gcd:=gcd(n, m mod n);{递归调用} end; begin { 主程序 } read (m,n); writeln (‘m=’,m ,’n=’,n ,’gcd=’, gcd( m,n) ); end.
第六次 递 归
递 归 pascal语言中,如果在一个函数、过程等定义内部又直接或间接地出现有对自身的引用,则称它们是递归的或者是递归定义的。 在程序中,递归是通过函数或过程的调用来实现的。函数或过程直接调用其自身,称为直接递归;函数或过程间接调用其自身,称为间接递归。
一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数).一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数). procedure b; procedure c; begin begin . . . . . c; b; . . . . end; end; 这种方式是间接调用. procedure fac; begin . . . fac; . . . end; 这种方式是直接调用.
如何设计递归算法 1.确定递归公式 2.确定边界(终了)条件
计算n!的函数 program hs_exam1; var i:integer;s :longint; function fac(n:integer):longint; var k:integer; t:longint; begint:=1; for k:=2 to n do t:=t*k;fac:=t; { 将计算结果值赋给函数,返回调用处 }end; begin read(n); s:=s+fac(n); write(‘s=‘,s); end.
例1阶乘函数可递归地定义为: 边界条件 递归方程 边界条件与递归方程是递归函数的二个要素,递归函数只有具备了这两个要素,才能在有限次计算后得出结果。
program p1(input,output); var n:integer;s:longint; function fac(a:integer):longint; begin if a=0 then fac:=1 else fac:=a*fac(a-1); end; begin readln(n); s:=fac(n); writeln(n,‘!=’,s) end.
程序: program p1(input,output); var n:integer;s:longint; function fac(a:integer):longint; begin if a=0 then fac:=1 else fac:=a*fac(a-1); end; begin readln(n); s:=fac(n); writeln(n,‘!=’,s) end. 1 1 a=0 {fac(0)} a=0 {fac(0)} 1 1 a=1 {fac(1)} a=1 {fac(1)} 2 2 a=2 {fac(2)} a=2 {fac(2)} 6 6 a=3 {fac(3)} a=3 {fac(3)} 24 24 a=4 {fac(4)} a=4 {fac(4)} 120 a=5 {fac(5)} a=5 {fac(5)} 栈用于存放递归调用中不断产生的新的局部变量
在调用过程或函数之前,系统需完成三件事: ⑴为被调用过程的局部变量分配存储区; ⑵将所有的实在参数、返回地址等信息传递给被调用过程保存; ⑶将控制转移到被调过程的入口。 从被调用过程返回调用过程之前,系统也应完成三 件工作: ⑴保存被调过程的计算结果; ⑵释放被调过程的数据区; ⑶依照被调过程保存的返回地址将控制转移到调用过程。
例输入一串以‘!’结束的字符,按逆序输出。例输入一串以‘!’结束的字符,按逆序输出。 program p4(input,output); procedure rever; var c:char; begin read(c); if c<>'!' then rever; write(c); end; begin {主程序} rever; end. 运行: 输入 hey! 输出 !yeh。 程序中,c 是过程rever的局部变量。每一次递归调用,都要为局部变量重新分配单元,因此各层的变量c实际上是不同的量,它们分别用于保存执行本层调用时的输入值。
hey! c=‘!’ procedure rever; var c:char; begin read(c); if c<>'!' then rever; write(c); end; c=‘y’ procedure rever; var c:char; begin read(c); if c<>'!' then rever; write(c); end; c=‘e’ procedure rever; var c:char; begin read(c); if c<>'!' then rever; write(c); end; c=‘h’ procedure rever; var c:char; begin read(c); if c<>'!' then rever; write(c); end;
program exam_jc; var n:integer;s:longint; function fac(a:integer):longint; begin if a=0 then fac:=1 else fac:=a*fac(a-1); end; begin readln(n); s:=fac(n); writeln(s) end. 调试
输入一串以‘!’结束的字符,按逆序输出。 program p4(input,output); procedure rever; var c:char; begin read(c); if c<>'!' then rever; write(c); end; begin {主程序} rever; end. 运行: 输入 hey! 输出 !yeh。 本例如果想输出为 Hey!!yeh 如何改
else 例4:输入一个非负数,输出这个数的倒序数。 Procedrue begin 输出n的最右边的一个数字; if 还有数字 then 将余下的“数字倒序” end Procedrue reverse(n:integer); var nr,nl:integer; begin nr:=n mod 10; write(nr); nl:=n div 10; if nl<>0 then reverse(nl) end;
例3、用递归方法求两个正整数m和n的最大公约数。例3、用递归方法求两个正整数m和n的最大公约数。 分析:求两个数的最大公约数可以用辗转相除法,即求m与n的最大公约数等价于求(m mod n)的值与n的最大公约数,此时的n可以当作新的m ,而(m mod n)的值当作新的n ,所以原问题的求解又变成求新的m与n的最大公约数问题,继续下去,直至(m mod n)为0,最大公约数就是最终存放在n中的值。 0 6 2
function gys(x,y:integer):integer; var z:integer; begin repeat z:=x mod y; x:=y; y:=z; until z=0;gys:=x; end;
递归公式: var m,n:longint ; function gcd(m,n:longint):longint; begin if m mod n=0 then gcd :=n else gcd:=gcd(n, m mod n);{递归调用} end; begin { 主程序 } read (m,n); writeln (‘m=’,m ,’n=’,n ,’gcd=’, gcd( m,n) ); end.
例5:用递归算法把任一给定的十进制正整数(<=32000)转换成八进制数输出。例5:用递归算法把任一给定的十进制正整数(<=32000)转换成八进制数输出。 分析:利用短除法不断除以8取余数这个重复过程,将原数据不断缩小,形成递归关系,当数据规模缩小至0时,递归结束。 procedure tran(n:longint); {递归过程} var k:longint; begin k:=n mod 8; {取除以8以后的余数} n:=n div 8; {取除以8以后的商} if n<>0 then tran(n); {直到商为0,结束递归过程} write(k:1) end;
1.var i,a,b,c,d:integer; f:array[0..3] of integer; begin for i:=0 to 3 do read(f[i]); a:=f[0]+f[1]+f[2]+f[3]; a:=a div f[0]; b:=f[0]+f[2]+f[3]; c:=(b*f[1]+a) div f[2]; d:=f[(b div c) mod 4]; if (f[(a+b+c+d) mod 4]>f[2]) then begin a:=a+b; writeln(a) end else begin c:=c+d; writeln(c);end; end. 输入: 9 19 29 39
2.procedure foo(a,b,c:integer); begin if a>b then foo(c,a,b) else writeln(a,',',b,',',c) end; var a,b,c:integer; begin readln(a,b,c); foo(a,b,c); end. 输入:2 1 3 输出:_________________ 1 3 2
3.procedure f(a,b,c:integer); begin write(a,b,c,'/'); If (a=3)and(b=2)and(c=1) then exit; if (b<c) then f(a,c,b) else if a<b then if a<c then f(c,a,b) else f(b,c,a); end; var a,b,c:integer; begin readln(a,b,c); f(a,b,c); end. 输入:1 3 2
var s:string; i,j,len,k:integer; begin readln(s);len:=length(s); for i:=1 to len do if (ord(s[i])>=ord('A')) and (ord(s[i])<=ord('Z')) then s:=chr(ord(s[i])-ord('A')+ord('a')); for i:=1 to len do if (ord(s[i])<ord('X')) then s:=chr(ord(s[i])+3) else s:=chr(ord(s[i])-23); write(s); write('/'); for j:=1 to 3 do begin i:=1; while i<=len-j do begin s[i]:=s[i+j];i:=i+j; end; end; writeln(s); end. 输入:ABCDEFGuvwxyz
以上是2008提高组初赛读程序题 32分
分析:折半查找是在一列升序或降序的数中查找目标数。设数放置在数组a中,top、mid、bot分别作为低、中、高指针,若需要查找的数是x,可以完成以下三种比较:分析:折半查找是在一列升序或降序的数中查找目标数。设数放置在数组a中,top、mid、bot分别作为低、中、高指针,若需要查找的数是x,可以完成以下三种比较: (1) 若x=a[mid],则表示找到。 (2) 若x<a[mid],则进行下一步查找,top不变,bot变成mid-1。 (3) 若x>a[mid],则进行下一步查找,top变成mid+1,bot不变。 显然,(2)、(3)出现了递归关系,数据规模在不断缩小,递归结束的条件有两个,要么找到,既x=a[mid];要么找不到,即出现top>bot 例5、用递归算法完成折半查找。 15 1511151926 374859 61 top mid bot
function search(top,bot:integer):Integer; var mid: integer; begin if top>bot then search:=-1 else begin mid:=(top+bot) div 2; if x=a[mid] then begin search:=mid; exit;end; else if x<a[mid] then search:=search(top,mid-1) else search:=search(mid+1,bot) end end;
思考: 0,1,1,2,3,5,8,13,21,34,55……从第三项起,每一项都是紧挨着的前两项的和。写出计算斐波那切数列的任意一个数据项递归函数形式。 function fic(m:integer):longint; begin if m=1 then fic:=0 if m=2 then fic:=1 ifm>2 then fic:=fic(m-1)+fic(m-2) {递归调用} end;
n=0 for i:=1 to 1 do write(1:3);writeln;p(0);for i:=1 to n do write(n:3);writeln; procedure p (n:integer); var i:integer; beginif n>0 then beginfor i:=1 to n do write(n:3);writeln; p(n-1);for i:=1 to n do write(n:3);writeln;end; end;执行P(4) n=0为边界条件不再展开 n=1 for i:=1 to 1 do write(1:3);writeln;p(0);for i:=1 to n do write(n:3);writeln; n=2 for i:=1 to 2 do write(2:3);writeln;p(1);for i:=1 to n do write(n:3);writeln; n=3 n=4 for i:=1 to n do write(3:3);writeln;p(2);for i:=1 to n do write(n:3);writeln; for i:=1 to 4 do write(4:3); writeln; p(3); for i:=1 to 4 do write(n:3);writeln;
第十二届全国青少年信息学奥林匹克联赛初赛试题 program ex404; var x,x2:longint; procedure digit(n,m:longint); var n2:integer; begin if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; end; begin writeln('Input a number:'); readln(x); x2:=1; while(x2<x) do x2:=x2*10; x2:=x2 div 10; digit(x,x2); writeln; end. 7次 输入: 9734526 n2=n mod 10 6次 n m x2 x 9734526 10000000 7位 8位 1000000 7位
n 9734526 973452 97345 if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; 97345 10000 9734 973452 100000 1000 9734 973 97 if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; 97 10 9 1 973 100 9 if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end; 6 2 5 4 3 7 9 9 7 3 4 5 2 6 第二个if语句后的n,是调用是的n,值参数据传递是单向的,数据不回带 n m 9734526 n2=n mod 10 1000000
递归要素:完成递归必须考虑的因素有两个。 (1)边界条件。也就是所描述问题的最简单情况,它本身不再使用递归的定义。如阶乘,当n=0时,f(n)=1,不使用f(n-1)来定义。 (2)递归关系。使问题向边界条件转化的规则。递归定义必须能使问题的规模越来越简单。 递归的优点:长处是,它能使一个蕴含递归关系且结构复杂的程序简介精炼,增加可读性。 特别是在难于找到从边界到解的全过程的情况下,如果把问题推进一步,其结果仍维持原问题的关系,则采用递归算法编程比较合适。递归的缺点:递归算法的效率往往很低,费时和费内存空间。
快速排序 • [分析]基本思想 • 快速排序的思想是:先从数据序列中选一个元素,并将序列中所有比该元素小的元素都放到它的右边或左边,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为1, 处理结束 设N个元素A[1..N],要求按非递减排序。 选择某一个元素X(一般取中间那个,初始时设i=1,j=N,则X=a[(i+j) div 2]),从两头(A[i]、A[j])开始逐个与X比较,找到左边比它大的那个元素A[i]和右边比它小的那个元素A[j],则交换A[i]与A[j] ,一举两得,然后inc(i)、dec(j)再继续进行,直到i>j。则这一趟结束,效果是X一定排在了它应该在的位置上了。
A 3 1 9 8 4 7 5 2 0 6 1 2 3 4 5 6 7 8 9 10 i j A 3 1 0 2 4 7 5 8 9 6 1 2 3 4 5 6 7 8 9 10 X Mid 然后,对X左右两边的部分进行类似的递归操作。实际上是一种二分思想,即把大于某个数的所有数交换到它的右边,而把小于它的数都交换到左边。如此这般递归下去,直到都符合要求为止。
例3、快速排序 [分析]基本思想 快速排序的思想是:先从数据序列中选一个元素,并将序列中所有比该元素小的元素都放到它的右边或左边,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为1, 处理结束. [编辑本段]算法过程 设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。一躺快速排序的算法是: 1)设置两个变量I、J,排序开始的时候:I=1,J=N; 2)以第一个数组元素作为关键数据,赋值给X,即 X=A[1]; 3)从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于X的值,让该值与X交换; 4)从I开始向后搜索,即由前开始向后搜索(I=I+1),找到第一个大于X的值,让该值与X交换; 5)重复第3、4步,直到 I=J;
program kspv; const n=7; Type arr=array[1..n] of integer; Var a:arr; i:integer; procedure sort(l,r:integer); var i,j,mid,t1:integer; begin i:=l;j:=r; mid:=a[(l+r) div 2]; {将当前序列在中间位置的数定义为中间数} repeat while a[i]< mid do inc(i); {在左半部分寻找比中间数大的数} while mid< a[j] do dec(j); {在右半部分寻找比中间数小的数} if i< =j then begin {若找到一组与排序目标不一致的数对则交换它们} t1:=a[j];a[j]:=a[i];a[i]:=t1; inc(i);dec(j); {继续找} end; until i >j; if l< j then sort(l,j); {若未到两个数的边界,则递归搜索左右区间} if i< r then sort(i,r); end;{sort} [35 28 46 17 15] i j 以中间元素为作为基准 begin write('input data:'); for i:=1 to n do read(a[i]); writeln; sort(1,n); write('output data:'); for i:=1 to n do write(a[i]:6); writeln; end.
开阔视野 由m个A,n个B组成若干个排列。从某个排列的位置1开始数,数到任意位置时都能保证A的个数不少于B的个数,则称该排列为合理排列。 例如:当m=2,n=2时排列有 A A B B(合理) A B A B(合理)A B B A(不合理) B B A A(不合理) 合理排列数有2种 输入:只有一行两个整数m,n(1≤n≤m≤12)(用 空格分隔) 输出:一个整数(所有的合理排列数) 【样例】 输入 输出 3 2 5
分析:模拟排队的情况,从第1个人开始,第1 人只能是A,第2个可以是A也可以是B,再其后的人要保证任意位置时都能保证A的个数不少于B的个数,递归生成整个排列。 Var m,n,t:LongInt; Procedure pd(i,j:LongInt); Begin If (i=m) And (j=n) Then t:=t+1{已生成一种排列} Else Begin If i<m Then pd(i+1,j);{增加1个A} If (j<n) And (j<i) Then pd(i,j+1); End; {增加1个B} End; Begin t:=0; Read(m,n);pd(1,0);Writeln(t); End.
汉诺塔(tower of Hanoi)问题。有n个大小不等的中空圆盘,按照从小到大的顺序迭套在立柱A上,另有两根立柱B和C。现要求把全部圆盘从A柱(源柱)移到C柱(目标柱),移动过程中可借助B柱(中间柱)。移动时有如下的要求: ①一次只移动一个盘; ②不允许把大盘放在小盘上边; ③可使用任意一根立柱暂存圆盘。
分析:首先将A柱上方的n-1个盘子从A柱移到B柱,此过程中C柱为中间柱;接着将A柱剩下的一个盘子移到C柱;最后再将B柱上的n-1个盘子移到C柱,此过程中A柱为中间柱,这就变成了移动n-1个盘子的问题了。定义过程hanoi,实现这一递归算法:分析:首先将A柱上方的n-1个盘子从A柱移到B柱,此过程中C柱为中间柱;接着将A柱剩下的一个盘子移到C柱;最后再将B柱上的n-1个盘子移到C柱,此过程中A柱为中间柱,这就变成了移动n-1个盘子的问题了。定义过程hanoi,实现这一递归算法: 若n=1,则A→C 若n>=2,则 hanoi(n-1,A,C,B) A→C hanoi(n-1,B,A,C) 运行结果:Enter the number of disks in Hanoi tower:3 A→C A→B C→B A→C B→A B→C A→C
语句: Hanoi(3,‘A’,‘B’,‘C’) 在执行过程中,递归工作栈要为每一层的递归保留数据,由于递归过程hanoi只含有四个值参数,也无其它局部变量,因而每一层递归需记录五个数据项:返回地址和四个值参。 (栈中内容为返回的程序行号,参数n,参数x,参数y,参数z)