C语言_ch07_2_函数递归和数组参数

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第7章 用函数实现模块化程序设计

来自百度文库
7.1为什么要用函数 7.2怎样定义函数


7.3调用函数
7.4对被调用函数的声明和函数原型 7.5函数的嵌套调用 7.6函数的递归调用 7.7数组作为函数参数
7.8局部变量和全局变量
7.9变量的存储方式和生存期 7.10 关于变量的声明和定义
同时有3个fact函数在 运行,且都未完成 main() { .... fact(2) } fact(2) fact(1) fact(0) { .... { .... { .... return 2*fact(1) return 1*fact(0) return 1 } } }
例2 互为素数的判断
2017/4/11
7
例1 求阶乘

n! fact(n) = 1 若n=0 n * fact(n-1) 若n>0
int fact(int n) { if (0 == n) return 1; return n * fact(n-1); }
2017/4/11 8
递归函数 fact( n )的执行过程
2017/4/11
21
数组元素作函数参数

例7.9 输入10个数,要求输出其中值最大的元素 和该数是第几个数。
2017/4/11
22
int main() { int nums[100], n; int indexMax = 0; // 最大元素对应下标 int i; scanf(“%d”, &n); for (i = 0; i < n; i++) scanf("%d", &nums[i]); for (i=1; i<n; i++) { 数组元素作为普通变量使用 // if (nums[i] > nums[indexMax]) if (max(nums[i],nums[indexMax]) > nums[indexMax]) indexMax = i; } printf("\nlargest number is %d\n", nums[indexMax]); printf("%dth number.\n", indexMax+1); } int max(int x, int y) { return x>y ? x : y; }
if (n == 1) // (出口)
move(a, 1, c); // 将编号为1的圆盘从a移到c else { hanoi(n-1, a, c, b); // 将a上n-1个圆盘移到b,c作辅助塔 move(a, n, c); } } int main() // 将编号为n的圆盘从a移到c hanoi(n-1, b, a, c); // 将b上n-1个圆盘移到c,a作辅助塔
例7.12 用选择法对数组中10个整数按由小到大排序。 解题思路:

所谓选择法就是先将10个数中最小的数与a[0]对换;再将 a[1]到a[9]中最小的数与a[1]对换……每一趟排序,找出 一个未经排序的数中最小的一个 共需9趟排序

2017/4/11
31
a[0] a[1] a[2] a[3] a[4]
3 1 1 1 6 6 3 3 1 3 6 4 9 9 9 9 4 4 4 6
(1)数据的定义是按递归定义的。

求阶乘:n!=1×2×3×……×n 或 n!=n×(n-1)! Fact(n) = 1 若n=0 n * Fact(n-1) 若n>0

Fibonacci函数(效率极其低下) Fib(n) =
0 若n=0 1 若n=1 Fib(n-1) + Fib(n-2) 若n>1
2017/4/11 16
例3:汉诺(hanoi)塔问题--递归的经典问题
在世界刚被创建的时候有一座钻石宝塔(塔A),其 上有64个金碟。所有碟子按从大到小的次序从塔底堆放 至塔顶。紧挨着这座塔有另外两个钻石宝塔(塔B和塔 C)。从世界创始之日起,婆罗门的牧师们就一直在试 图把塔A上的碟子移动到塔C上去,其间借助于塔B的帮 助。每次只能移动一个碟子,任何时候都不能把一个碟 子放在比它小的碟子上面。有预言说,这件事完成时宇 宙会在一瞬间闪电式毁灭. 按1秒钟挪动一块计算,要把64块黄金圆盘挪动完, 要用5800亿年时间,而现在宇宙的年龄只有大约150亿年。
数组名作函数参数

用数组元素作实参时,向形参变量传递的是数组 元素的值 用数组名作函数实参时,向形参传递的是数组首 元素的地址

2017/4/11
24

例7.10 有一个一维数组score,内放10个学生成绩, 求平均成绩。 解题思路:


用函数average求平均成绩,用一维数组作为函数 形参

如何证明两个整数互为素数。
例:314159与271828互为素数的证明。
如果两个整数的最大公约数为1,则两数互为素数。
2017/4/11
10
求最大公约数----欧几里得算法

两个整数x和y(x>y)的最大公约数与y和x%y的 最大公约数相同。也叫辗转相除法。 x (当y=0)
gcd(x,y) =
递归(recursion)的定义

调用自身的程序 问题分解:把一个不能或 不好解决的大问题转化为 一个或几个小问题,再把 这些小问题进一步分解成 更小的小问题,直至每个 小问题都可以直接解决。

递归的基本思想

德罗斯特效应—递归的视觉效应
2017/4/11
4
递归应用

递归算法一般用于解决三类问题:
5
2017/4/11

(2)数据的结构形式是按递归定义的

树的遍历 图的搜索

(3)递归求解比迭代求解更简单的问题


八皇后
Hanoi汉诺塔问题
2017/4/11
6
递归算法

优点:简洁、紧凑而优雅(elegant) 递归两要素(写出递归算法的关键)

⑴ 递归出口:确定递归到何时终止; ⑵ 递归式:大问题是如何分解为小问题的,也 称为递归体。每次递归调用必须使用一个更小 的参数值。 解题步骤: 分析问题 递归要素 设计算法
// Fibonacci.c 求Fibonacci数列 int fib(int n); //原型声明 int main() { int i; for (i=0; i<10; ++i) { printf("fib(%d): %d\n", i, fib(i)); } return 0; } int fib(int n) { if (n == 0) return 0; if (n == 1) return 1; return fib(n-1) + fib(n-2); }
int i;
float aver, sum = array[0]; for (i=1; i<10; i++) sum = sum + array[i];
aver = sum / 10;
return aver; }
2017/4/11
27

例7.11 有两个班级,分别有35名和30名学生,调 用一个average函数,分别求这两个班的学生的平 均成绩。
scanf("%f", &scores[i]);
printf("\n");
只传数组名
aver = average(scores); // average(scores[10])错误,? printf("%5.2f\n", aver); return 0; }
2017/4/11
26
float average(float array[]) {

2017/4/11
19
void move(char x, int n, char z) { }
// 第n个圆盘从塔x搬到塔z
printf("将%d号盘从%c移到%c\n", n, x, z);
void hanoi(int n, char a, char b, char c) // 算法3.5 { // 将a塔上编号为1至n的n个圆盘借助b塔移到c塔
2017/4/11
17
2017/4/11
18
汉诺塔问题的递归求解

如果 n = 1,则将这一个盘子直接从塔A移到塔 C 上。否则,执行以下三步: ⑴ 将塔A上的n-1个碟子借助塔C先移到塔B上; ⑵ 把塔A上剩下的一个碟子移到塔C上; ⑶ 将n-1个碟子从塔B借助于塔A移到塔C上。 伪码到C源码的能力
gcd(y, x%y) (x>y 且 y不为0)
2017/4/11
11

例:314159与271828互为素数的证明。
gcd(314159, 271828) =
gcd(271828, 42331) = gcd(42331, 17842) =
gcd(17842, 6647) =
gcd(6647, 4458) = gcd(4458, 2099) = gcd(2099, 350) = gcd(350, 349) =
求出的平均成绩返回main函数

2017/4/11
25
float average(float array[]); //float array[10]也可以,编译器忽略10
int main() {
float scores[10], aver;
int i; printf("input 10 scores:\n"); for (i=0; i<10; i++)
float average(float { int i; float aver, sum for (i = 1; i < sum = sum + aver = sum / n; return aver; }
array[], int n)
= array[0]; n; i++) array[i];
30

2017/4/11
28

解题思路:

需要解决用同一函数求两个不同长度的数组的 平均值的问题 定义average函数时,参数除了数组地址,增 加一个表示数组长度的整型形参n

2017/4/11
29
float average(float array[], int n); int main() { float score1[5] = {98.5,97,91.5,60,55}; float score2[10] = {67.5,89.5,99,69.5,77, 89.5,76.5,54,60,99.5}; printf(“average of score1 : %6.2f\n", average(score1, 5)); printf("average of score2 : %6.2f\n", average(score2, 10)); return 0; }
{
int n; printf(“3个塔座为a、b、c,圆盘最初在a塔,借助b塔移到c塔。\n请输入圆盘数:"); scanf("%d", &n); hanoi(n, 'a', 'b', 'c'); }
7.7 数组作为函数参数

7.7.1 数组元素作函数实参 7.7.2 一维数组名作函数参数 7.7.3 多维数组名作函数参数
gcd(349, 1) =
gcd(1, 0) =1
2017/4/11 12
//欧几里得算法的递归形式 int gcd(int x, int y) { if (y==0) return x; return gcd(y, x%y); }
2017/4/11
13
//欧几里得算法的迭代形式
int gcd(int x, int y) { int r; while (y != 0) { r = y; y = x % y; x = r; } return r; }
2017/4/11
14
反例 Fibonacci函数

分解成的子问题必须是独立的子问题
fib(n) =
0 若n=0 1 若n=1 fib(n-1) + fib(n-2) 若n>1

T(fn+1) = 1.6T(fn), 指数时间 求 F( 5 ) f(5)=f(4)+f(3); f(4)=f(3)+f(2); f(3)=f(2)+f(1); 其中f(3),f(2),f(1)都求解2次。这显然会 增加时间复杂度。

7.11 内部函数和外部函数
1
2017/4/11
递归(Recursion)

函数直接或间接调用自己为递归
int fact(int n) { if (0 == n) return 1; else return n * fact(n-1); }
2017/4/11
2
2017/4/11
3
递归的实现

相关文档
最新文档