0.引入
例子:
int a[10];
int i;
for( i=0; i<10; i++ )
{
scanf("%d", &a[i] );
}
int b[5];
for( i=0; i<5; i++ )
{
scanf("%d", &b[i] );
}
int c[7];
int d[20];
....
在程序中,,需要给多个数组从键盘上获取值
以上的代码, 功能都是一样, 都是为了从键盘上获取值
不一样的是 数组名 和 数组元素的个数, 代码形式也是一样的
对于同一个功能 而 参数不同的 代码块, 我们就可以用函数 来进行概括
函数 --> 重复利用代码块
1.函数
function 功能
函数 是完成某一个功能的指令序列的封装
C语言的指令必须在函数的内部
函数可以实现代码复用, 以及实现 模块化的设计
函数的特点:
相同功能的代码块,重复利用,模块化设计思想
2.如何来封装函数?
函数是用来实现某一个功能或者任务
实现任务:
之前: 我们考虑完成这个任务需要哪些资源? 是0个还是多个资源?
中间: 思路(算法)
之后: 完成这个任务能给给我什么影响?
设计函数的步骤:
(1)明确函数的功能是什么? (函数功能)
起函数名:
符合C语言合法标识符的定义规则, 尽量做到 "见其名 知其意"
(2)考虑完成该函数需要哪些已知条件/资源? (输入参数)
输入完成该任务所需要的参数
例如:
完成一个任务"找数组中的最大值"
此时,编译器完成这个任务时 需要知道该数组的信息
比如说这个哪个数组的最大值(数组名)? 这是一个什么样的数组(数组元素的类型)?
这个数组有多大(元素个数)?
(3)考虑完成该任务之后的输出结果? (返回值)
确定函数的返回值的类型
例如:
完成一个任务"找数组中的最大值"
那么当任务完成之后,如果找到了这个最大值,
我们是希望编译器能够告诉我这个最大值到底是多少?
(4)算法实现 以及 调试部分
例子:
完成一个任务: 求两个整数之和
(1)明确功能
起函数名: ---> sum()
(2)找出完成该任务所需要的资源
输入参数: ---> 两个整数
---> sum( int a, int b )
(3)完成任务后的输出结果
确定函数的返回值的类型
结果: 之和 ---> int
--->
int sum( int a, int b )
{
}
(4)算法实现以及调试部分
int sum( int a, int b )
{
//算法实现
int s;
s = a + b;
return s;
}
3.在C语言中 函数的定义语法
语法:
返回值类型 函数名(参数列表) //函数头
{
C语句;
return 表达式;
}
函数的三要素:
"返回值类型" :
return语句 后面的那个表达式的值 的类型
一般是"单值类型", 即基本类型和指针类型
函数也可以不返回值的 ---> void
不指定函数的返回值类型 ---> 默认为 int
"函数名"
符合C语言合法标识符的定义规则, 尽量做到 "见其名 知其意"
"参数列表"
类型1 参数名1, 类型2 参数名2, ....
为void 表示该函数不带任何参数, 此时void可省略
return
返回的意思, return只能在函数内部, 表示函数返回/结束的意思
return 表达式; //表示函数结束,带有一个返回值,这个返回值就是表达式的值
//函数的返回值类型 就是return语句后面的表达式值的类型
return ; //后面不带表达式 表示函数结束,不带任何返回值
注意:
函数不能嵌套定义,也就是说函数不能定义在别的函数里面,只能定义在外面
练习:
1)设计一个函数,求两个整数之差
int sub( int a, int b )
{
return a>b ? a-b : b-a ;
}
4.函数的调用
函数调用, 调用一个已经写好的函数 去执行
1)如何调用函数?
(1)需要指定是哪个函数 ----> 函数名
(2)指定完成该函数的参数 ----> 实际参数, 简称:实参
主调函数 : 调用其他函数的这个函数 , 比如: main()
被调函数 : 被其他函数所调用的那个函数, 比如: sub() "相对的概念"
实际参数 (实参)
在函数调用的过程中, 主调函数传递给被调函数的参数的值, 比如: sub( 5 , 2 );
形式参数 (形参)
被调函数 定义的时候的参数, 简称:形参, 比如: sub( int a, int b )
注意:
(1)在函数调用时, 需要指定"实参", 并且 实参和形参 要一一对应( 数据类型, 参数个数 )
(2)在C语言中, 函数的参数的传递 只有一种情况: "值传递"
就把实参的值传递给相应的形参
"值传递" : 形参 = 实参; //赋值
例子:
int sum(int a, int b)
{
return a+b;
}int m=3, n=5;
sum( 3, 5 ); // OK 8
sum( 2+3, 5+6 ); // OK 16 // 先会计算出实参的值, 再将实参的值 传递给 形参
sum( m, n ); // OK 8
sum( m*n+3, m/n+4 ); // OK 22
sum( sum(4,6), 5 ); // OK 15
// sum(4,6) ==> 10 "函数调用表达式" --> 该表达式的值就该函数的返回值
// sum( 10 , 5 ) ==> 15
int c = sum( 1, 2 ); // Ok c ==> 3sum( 4, 6, 5 ); // error
2)函数调用的过程
int sum( int a, int b )
{
int s;
s = a + b;
return s;
}int main()
{
int m=3, n=4;
int c = sum( m, n );
printf("c = %d\n", c ); //7
return 0;
}
函数调用的过程:
(1)把实参的值传递给形参 (先会计算出实参的值, 再传递给形参)
(2)跳转到指定的被调函数去执行, 直到遇到return或者函数执行完毕,
再返回到主调函数 调用的位置
return后面的表达式的值, 将作为整个"函数调用表达式"的值
5.数组作为函数的参数
当一个函数的参数是数组时, 该如何去描述?
1)一维数组
数据元素的类型 数组名[整型表达式];
int a[10];
需要定义两个变量:
m代码a这个数组的名字
n代码a这个数组的元素个数
==>
int xxx( int m[], int n )
{
}
调用时: xxx( a, 10 );
2)二维数组
int b[3][4]; //数组b实际上就是一个一维数组, 里面有3个元素, 每一个元素都是 int [4] 类型
需要定义两个变量:
a代码b这个数组的名字
n代码b这个数组的元素个数
===>
int yyy( int a[][4], int n )
{
}
调用时: yyy( b, 3 );
===>
m代表行
n代表列
int zzz( int m, int n, int a[][n] )
{
}
调用时: zzz( 3, 4, b );
练习:
1)写一个函数, 实现对一个一维整型数组的输入(从键盘上获取值)
再写一个函数,实现对一个一维整型数组的输出(打印到终端上)
void input_array( int a[], int n )
{
int i;
for( i=0; i<n; i++ )
{
scanf("%d", &a[i] );
}
}void output_array( int a[], int n )
{
int i;
for( i=0; i<n; i++ )
{
printf("%d ", a[i] );
}
putchar('\n');
}int main()
{
int a[5];
input_array( a, 5 );
output_array( a, 5 );int b[7];
input_array( b, 7 );
output_array( b, 7 );
}
2)设计一个函数, 求一个一维数组中的最大值,通过返回值将最大值返回
(1) find_array_max()
(2) find_array_max( int a[], int n )
(3) int find_array_max( int a[], int n )
(4) 实现
==>
int find_array_max( int a[], int n )
{
int max = a[0]; //记录最大值
int i;
for( i=0; i<n; i++ ) //遍历数组
{
if( a[i] > max )
{
max = a[i];
}
}
return max;
}
6.函数声明
"声明" :
在C语言中, 声明 是用来声明一个已经存在的标识符(对象的名字)
声明就是用来表示一个标识符(对象的名字)到底是什么东西
为什么需要声明?
C语言编译源文件时, 是从第一行到最后一行, 一行一行的进行编译
而且在编译多个文件的时候, 也是一个文件一个文件的编译的
有时候1.c可能会用到2.c中定义的对象(变量/函数等)
在编译1.c时,碰到这个对象的名字, c语言编译器就可能不认识这个标识符,
即使是在同一个文件中, 在前面碰到的标识符,而这个标识符的定义在后面
此时 编译器也会不知道这个标识符是什么东西
一般来说, 在源文件的前面 要进行标识符的声明
约定:
将声明 放在 使用的前面
声明的格式:
(1) 外部变量的声明
extern 变量的类型 变量名; //外部变量声明时, 不能给它初始化
(2) 函数的声明
(2.1) 外部函数的声明:
extern 函数的返回值类型 函数名(参数列表); //extern 函数头;
(2.2)本文件内部的 函数的声明
函数的返回值类型 函数名(参数列表); // 函数头;
例子:
04外部变量1.c 05外部变量2.c
注意:
函数声明,形参的名字是可以省略的,但是类型不能省略
int sum( int x, int y ); // OK
int sum( int, int); // OK
int sum( x, y ); // error
====================================
.h 头文件 (接口文件)
头文件的格式:
例子: sum.h
#ifndef __SUM_H__ //防止重复包含
#define __SUM_H__
//头文件 一般包含 宏定义, 函数声明, 类型构造等
#endif
头文件的引用
#include <> 从系统标准的头文件路径下进行搜索 (如: /usr/include/ )
#include "" 先从当前的工程路径下进行搜索, 再从系统标准的头文件路径下进行搜索
练习:
1)写一个函数, 判断一个一维整型数组是否有序 (升序||降序)
返回值:
1 有序
0 无序
(1) is_sort()
(2) is_sort( int a[], int n )
(3) int is_sort( int a[], int n )
(4) 实现
===>
int is_sort( int a[], int n )
{
int flag = 1; // 升序 标志位
int sign = 1; // 降序 标志位int i;
for( i=0; i<n-1; i++ )
{
//升序
if( a[i] > a[i+1] ) //找出一个反例
{
flag = 0;
}//降序
if( a[i] < a[i+1] ) //找出一个反例
{
sign = 0;
}
}if( flag || sign )
{
return 1; //有序
}
else
{
return 0; //无序
}
}
2) 将一个整数x, 插入到一个递增数组中, 使得插入后的数组仍然有序
例子:
int a[10] = {1,3,5,7,9,11,13,15,17 };
x = 6;
---> 1,3,5,6,7,9,11,13,15,17
思路:
找到待插入的位置 (找到第一个比它大的数的前面进行插入)
进行插入操作
算法一: 直接插入排序
int main()
{
int a[10] = {1,3,5,7,9,11,13,15,17 };
int x;
scanf("%d", &x );//1.找到待插入的位置 (找到第一个比它大的数的前面进行插入)
int i,j;
for( i=0; i<9; i++ )
{
if( a[i] > x )
{
//找到了
break;
}
}//找到了 , 进行插入操作
if( i != 9 )
{
//先把原来的数据 往后移
for( j=9; j>i; j-- )
{
a[j] = a[j-1];
}
}//再进行插入 (没有找到i==9,说明x就是最大的, 直接将x放在末尾 )
a[i] = x;for( i=0; i<10; i++ )
{
printf("%d ", a[i] );
}
putchar('\n');
}
算法二: 二分插入
int main()
{
int a[10] = {1,3,5,7,9,11,13,15,17 };
int x;
scanf("%d", &x );//1.找到待插入的位置 --> 二分查找
int l = 0; //最左边的元素的下标
int r = 8; //最右边的元素的下标
int mid; //中间位置while( l <= r )
{
mid = (l+r) / 2 ;if( x < a[mid] )
{
r = mid - 1;
}
else if( x > a[mid] )
{
l = mid + 1;
}
} //当while结束时,l就指向带插入的位置
//2.插入操作
int i;
for( i=9; i>l; i-- ) //将较大值往后移
{
a[i] = a[i-1];
}a[l] = x; //插入
for( i=0; i<10; i++ )
{
printf("%d ", a[i] );
}
putchar('\n');
}
3)写一个函数, 求一个无符号的32位整数x的二进制形式有多少个1?
返回值: 返回1的个数
x = 7; ---> 00000000 00000000 00000000 0000 0111 --> 3
思路:
分别判断这个数的每一个bit位
算法一:
int bit_count( unsigned int x )
{
int num = 0; //记录 1的个数
int i;
for( i=0; i<32; i++ )
{
if( x & (1<<i) ) //判断这个数的每一个bit位 是否为1
{
num++;
}
}
return num;
}
算法二:
int bit_count_v2( unsigned int x )
{
int num = 0; //记录 1的个数
int i;
while( x )
{
if( x & 1 )
{
num++;
}
x = x >> 1;
}
return num;
}
算法三:
int bit_count_v3( unsigned int x )
{
int num = 0; //记录 1的个数
int i;
while( x )
{
if( x % 2 ) //除2取余法
{
num++;
}
x = x / 2;
}
return num;
}
算法四:
x = x & (x-1);00000000 00000000 00000000 1111 1100 x
00000000 00000000 00000000 1111 1011 x-1
& ---------------------------------------------
00000000 00000000 00000000 1111 1000 x
00000000 00000000 00000000 1111 0111 x-1
& ----------------------------------------------
....int bit_count_v4( unsigned int x )
{
int num = 0; //记录 1的个数
int i;
while( x )
{
x = x & (x-1);
num++;
}
return num;
}
4) 把一个二维数组的行和列 进行互换
a[3][4] ==> b[4][3]
1,2,3,4 1,5,9
5,6,7,8 2,6,10
9,10,11,12 3,7,11
4,8,12
a[0][0] ==> b[0][0]
a[0][1] ==> b[1][0]
a[0][2] ==> b[2][0]
...
a[i][j] ==> b[j][i]
===>
int main()
{
int a[3][4];
int i,j;
for( i=0; i<3; i++ )
{
for( j=0; j<4; j++ )
{
scanf("%d", &a[i][j] );
}
}//进行行列互换
int b[4][3];
for( i=0; i<4; i++ )
{
for( j=0; j<3; j++ )
{
b[i][j] = a[j][i]; //行列互换
}
}for( i=0; i<4; i++ )
{
for( j=0; j<3; j++ )
{
printf("%d ", b[i][j] );
}
putchar('\n');
}
}
5) 写一个函数, 输入一个正整数n, 求距离它最近的质数
如果它本身就是质数, 就打印本身
如果有两个,打印较小的那个
例如:
7 --> 7
15 --> 13, 17 --> 13
n 判断n是否为质数
n-1 判断n-1是否质数
n+1 判断n+1是否质数
n-2
n+2
...
/*
is_primary : 判断一个数是否为质数
返回值:
1 是质数
0 不是质数
*/
int is_primary( int n )
{
if( n < 2 )
{
return 0;
}int i;
for( i=2; i<n; i++ )
{
if( n%i == 0 )
{
return 0; //不是质数
}
}
return 1; //是质数
}//求距离n最近的质数
int get_closest_primary_num( int n )
{
int i = 0;
while( 1 )
{
if( is_primary( n-i ) ) //n, n-1, n-2, ...
{
return n-i;
}
if( is_primary( n+i ) ) //n, n+1, n+2, ....
{
return n+i;
}
i++;
}
}int main()
{
int n;
scanf("%d", &n );int x = get_closest_primary_num( n );
printf("距离最近的质数为 %d \n", x );
}
7.变量的作用域和生存期
1)作用域
一个对象(变量\数组\函数等) 起作用的范围
(1)全局变量
在函数外面定义的变量, 叫 全局变量
如果全局变量在定义的时候没有初始化, 那么编译器会自动初始化为0
全局变量的作用域:
自定义起 往下到文件结束 (别的文件也可以使用, 但是要extern外部变量声明)
但是, 如果一个全局变量被static修饰, 这个全局变量的作用域 就被限制 仅在本文件中使用
被static修饰的变量, 只能初始化一次
如果没有被初始化, 那么编译器也会被初始化为0
(2)局部变量
在 函数体内 或者 复合语句内 定义的变量, 叫 局部变量
局部变量的作用域:
自定义起 到 函数结束 或者 复合语句结束 (即第一个右花括号的位置)
注意:
不用作用域的两个变量, 必然是两个独立的空间
哪怕名字重复了, 就近往上找
例子:
1)
//全局变量
int b = 5;
int d;int main()
{
int a = 10; //局部变量printf("b = %d\n", b ); // 5 全局变量
int b = 6; //局部变量
printf("b = %d\n", b ); // 6 局部变量,就近往上找if(a == 10 )
{
int c; //局部变量
printf("c = %d\n", c ); //未知的,不确定的
}
//printf("c = %d\n", c ); //超出作用域了int c = 6;
printf("c = %d\n", c );//int c = 6; //error 重复定义,一个作用域下不能有两个同名
for( int i=0; i<5; i++ ) // i 局部变量
{
printf("d = %d\n", d ); //被自动初始化为0
}
//printf("i = %d\n", i ); //超出作用域了
}
2)
int a = 5;
int main()
{
printf("a = %d\n", a ); // 5
int a = 6;
if( 1 )
{
int a = 7;
printf("a = %d\n", a ); // 7
}
printf("a = %d\n", a ); // 6
}
3)
void exchange( int a, int b )
{
int temp = a;
a = b;
b = temp;
}int main()
{
int a = 5, b = 6;exchange( a, b ); //形不改实, 并没有交换实参的值, 实参只是把值传递给了的形参
printf("a = %d, b = %d\n", a, b ); // 5 6
}
2)形不改实 ☆☆☆
当主调函数 调用 被调函数时, 且实际参数是 变量
则 被调函数中的形参的变化 不会影响到实参的变化
原因:
形参只是被调函数里面的局部变量, 与实际参数是两个独立的空间
函数调用时 只是把实参的值 传递(赋值)给了 形参而已, 二者互不影响
3)生存期
是指一个对象从生到死的期间(生成周期)
一个变量过了它的生存期, 其内存空间就会被释放掉
全局变量的生存期:
随进程的持续性 (进程:正在进行程序)
你的程序一直运行, 全局变量就会一直存在, 直到进程退出为止
局部变量的生存期:
(1)普通局部变量
int a;
普通的局部变量, 自定义起 到函数结束 或者 复合语句结束 (即第一个右花括号的位置)
例子:
void func()
{
int a = 7;
a++;
printf("a = %d\n", a );
}int main()
{
func(); // 8
func(); // 8
}
(2)static 静态局部变量
static int a; // 静态局部变量
static静态局部变量 的生存期:
随进程的持续性, 且只初始化一次
例子:
void func()
{
static int a = 7;
a++;
printf("a = %d\n", a );
}int main()
{
func(); // 8
func(); // 9
}
☆☆☆
总结:
static在C语言中的作用:
(1)static用于 修饰 全局变量 或者 函数 的时候
被修饰的全局变量或者函数的作用域, 变为 仅在本文件中使用
(2)static用于 修饰 局部变量 的时候
使得被修饰的局部变量的生存期, 变为随进程的持续性, 且初始化只执行一次
8.递归函数
递归函数: 直接或者间接调用函数本身 "自己调用自己"
什么是才能使用递归?
解决一个问题时, 解决思路转换为与问题本身类似的问题
☆☆☆
递归函数的设计思想:
(1)问题模型本身要符合递归模型(弄清楚递推关系)
(2)先明确函数 要实现的功能(函数名)和参数之间的关系, 暂时不管功能的具体实现
(3)问题的解, 当递归到一定程度时, 答案是显而易见的, 并且能够结束递归(不能无限递归)
(4)要呈现出 第n层 和 第n-1层 的递推关系
例子:
1)写一个函数, 实现求第n个人的年龄
第一个人的年龄是10岁, 第二个人的年龄是12岁, 第三个人14岁.... 依次类推
a[0] -- 10
a[1] -- 12 --> a[0] + 2
a[2] -- 14 --> a[1] + 2
...
a[n-1] --> a[n-2] + 2
a[n] --> a[n-1] + 2
算法一: 普通方法
int get_age( int )
{
int a[n];
a[0] = 10;
int i;
for( i=1; i<n; i++ )
{
a[i] = a[i-1] + 2;
}
return a[n-1];
}
算法二: 递归方法
(1)除了第一个人以外, 其余所有人的年龄 都是前一个人的年龄加2
(2)
int get_age( int n )
{}
得到第n个人的年龄 get_age( n-1 ) + 2
得到第n-1个人的年龄 get_age( n-2 ) + 2
...
得到第3个人的年龄 get_age( 2 ) + 2
得到第2个人的年龄 get_age( 1 ) + 2
得到第1个人的年龄 10
当 n == 1 时,
return 10;
(3) 当n==1时, 答案是显而易见的, 是10岁
(4) get_age(n) ==> get_age(n-1) + 2
==>
int get_age( int n )
{
if( n == 1 )
{
return 10;
}
else
{
return get_age(n-1) + 2;
}
}
2) 设计一个递归函数, 实现求n的阶乘 n!
(1) 0! = 1
1! = 1
2! = 1*2 --> 1! * 2
3! = 1*2*3 --> 2! * 3
4! = 1*2*3*4 --> 3! * 4
...
n! = (n-1)! * n
(2) int factorial( int n )
{}
(3) 当 n==0 或者 n==1 时, 答案是显而易见的, 为 1
(4) factorial(n) ==> factorial(n-1) * n
===>
int factorial( int n )
{
if( n==0 || n==1 )
{
return 1;
}
else
{
return factorial(n-1) * n;
}
}
3)汉诺塔 Hanoi
把n个盘子, 从A柱 移动到 C柱, 中间可以使用B柱, 大盘子不能在小盘子的上面
请把移动的步骤 和 总步数 打印出来
(1)
当 n == 1
打印 : A --> C , step = 1
当 n == 2
打印 :
A --> B
A --> C
B --> C step = 3
n == 3
....
n
1.先把A上面的 n-1个盘子 从A柱 移动到 B柱
2.然后把第n个盘子 移动到 C柱
3.最后 把n-1个盘子 从B柱 移动到 C柱
(2)
int step = 0; //全局变量 保存总步数
//把n个盘子, 从A柱 移动到 C柱, 中间可以使用B柱
void Hanoi( int n, char A, char B, char C )
{
}
(3) 当n==1 和 n==2时, 答案是显而易见的
(4)
Hanoi( n , A, B, C )
==>
//1.先把A上面的 n-1个盘子 从A柱 移动到 B柱
Hanoi( n-1, A, C, B );
//2.然后把第n个盘子 移动到 C柱
printf("%c --> %c\n", A, C );
//3.最后 把n-1个盘子 从B柱 移动到 C柱
Hanoi( n-1, B, A, C );
====>
int step = 0; //全局变量 保存总步数//把n个盘子, 从A柱 移动到 C柱, 中间可以使用B柱
void Hanoi( int n, char A, char B, char C )
{
if( n == 1 )
{
printf("%c --> %c\n", A, C );
step++;
return ;
}
else if( n == 2 )
{
printf("%c --> %c\n", A, B );
step++;
printf("%c --> %c\n", A, C );
step++;
printf("%c --> %c\n", B, C );
step++;return ;
}
//1.先把A上面的 n-1个盘子 从A柱 移动到 B柱
Hanoi( n-1, A, C, B );//2.然后把第n个盘子 移动到 C柱
printf("%c --> %c\n", A, C );
step++;//3.最后 把n-1个盘子 从B柱 移动到 C柱
Hanoi( n-1, B, A, C );return ;
}
递归函数的参数:
(1)每次递归处理的是不同的对象 ---> 对象作为参数
(2)每次递归处理的同一个对象 ---> 可以用全局变量, 也可以传指针作为参数
(3)把子问题解决之后, 需要回传解 ---> 返回值
9.快速排序
分治法:
分而治之, 将问题分解成规模更加小的子问题
算法:
对于一个数组, 从中间位置选择一个元素, 以该元素为界 将其余元素划分成两个子集
一个子集中所有的元素都是小于该元素的, 另一个子集中的所有元素都是大于该元素的
再对这样的两个子集 递归执行以上的这一过程
当某个子集的元素个数小于2个时, 这个子集就不需要再排序了,终止递归
时间复杂度: O( n * log以2为底n )
实现:
//交换数组的两个元素的位置
void swap( int a[], int i, int j )
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}//快速排序
void quick_sort( int a[], int left, int right )
{
if( left >= right )
{
return ;
}//1.从中间位置选择一个元素, 以该元素为界 将其余元素划分成两个子集
swap( a, left, (left+right)/2 );
//划分
int i;
int last = left; //代表左边子集的最后一个元素的下标
for( i=left+1; i<=right; i++ )
{
if( a[left] > a[i] )
{
swap( a, i, ++last );
}
}
swap( a, left, last );//2.左边的子集
quick_sort( a, left, last-1 );//3.右边的子集
quick_sort( a, last+1, right );}
10.总结
(1)掌握函数的基本语法, 设计步骤, 函数调用, 数组作为函数的参数
(2)声明
(3)作用域和生存期
(4)递归函数的设计思想(步骤)
(5)快速排序的算法思想
练习:
1)设计一个递归函数, 实现求一个一维数组的所有元素之和
(1)
s1 = a[0]
s2 = a[0] + a[1] == s1 + a[1]
s3 = a[0] + a[1] + a[2] == s2 + a[2]
...
Sn = S(n-1) + a[n-1]
(2)
int array_sum( int a[], int n )
{}
(3) 当 n==1 时, 答案是显而易见的, 元素之和为 a[0]
(4) array_sum( a, n ) ==> array_sum( a, n-1 ) + a[n-1]
===>
int array_sum( int a[], int n )
{
if( n == 1 )
{
return a[0];
}
else
{
return array_sum(a, n-1) + a[n-1];
}
}
2)设计一个递归函数, 判断一个一维整型数组是否递增
返回值:
1 是
0 不是
(1)
a[0] 1个元素
a[0] < a[1] 2个元素
a[0] < a[1] && a[1] < a[2] 3个元素
a[0] < a[1] && a[1] < a[2] && a[2] < a[3] 4个元素
...
a[0] < a[1] && a[1] < a[2] && a[2] < a[3] && .... && a[n-2] < a[n-1] n个元素
(2)
int is_up( int a[], int n )
{}
(3) 当 n==1 时, 答案是显而易见的, return 1; //是
(4)
n个元素 要满足的关系是:
前面n-1个元素都满足递增关系 && a[n-2] < a[n-1]
===>
int is_up( int a[], int n )
{
if( n == 1 )
{
return 1;
}
else
{
return is_up( a, n-1 ) && a[n-2] < a[n-1];
}
}