一、重点内容
1.函数的定义
函数应该先定义后使用。
函数定义的语法形式:
数据类型 函数名(形式参数表)
{
函数体 //执行语句
}
注意:
(1)函数的数据类型是函数的返回值类型,若数据类型为void,则无返回值。
(2)函数名是标识符,一个程序中除了主函数名必须为main外,其余函数的名字按照标识符的取名规则可以任意选取。
(3)形式参数表可以是空的,也可以有多个形参,形参间用逗号隔开,不管有无参数,函数名后的圆括号都必须有。形参必须有类型说明,形参可以是变量名、数组名或指针名,它的作用是实现主调函数与被调函数之间的关系。
(4)函数不允许嵌套定义。在一个函数内定义另一个函数是非法的,但是允许嵌套使用。
例:定义一个函数,返回两个数中的较大数。
int main(int x,int y)
{
return x>y? x:y;
}
2.函数调用
为函数分配存储空间,执行函数。被其他函数调用的函数成为被调用函数,调用其他函数的函数,称为调用函数。
3.函数声明
为了避免函数在定义前调用,在调用前声明这个函数的原型。
一般形式如下:
类型标识符 函数名(形参表); 一定要以分号结束
4.函数调用时的三种参数传递方式
(1)按值传递:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间;然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。 (只对形参进行操作)
void swap(int a,int b)
{
int tmp=a;a=b;b=tmp;
}
int main()
{
int c=1,d=2;
swap(c,d);
cout<<c<<" "<<d<<endl;
return 0;
}
此段程序虽然在swap函数中交换了a,b两数的值,但它并没有改变实参的值。
(2)地址传递:如果在函数定义时将形参说明成指针,调用函数时就需要指定地址值形式的实参。这时的参数传递方式就是按地址传递方式。
按地址传递与按值传递的不同在于:形参指针的实参指针指向同一个地址。
void swap(int*x,int *y)
{
int t=*x;
*x=*y;
*y=t;
}
//………
swap(&a,&b);
(3)引用传递:在函数定义时在形参前面加上引用运算符“&”。
void swap(int &x,int &y)
{
int t=x;
x=y;
y=t;
}
//……
swap(a,b);
5.递归函数
定义:直接或间接调用自身的函数称为递归函数。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
递归的关键在于找出递归定义和递归终止条件。
递归定义:使问题向边界条件转化的规则。递归定义必须能使问题越来越简单。
递归终止条件:也就是所描述问题的最简单情况,它本身不再使用递归的定义。
解题步骤:
(1)分析问题、寻找递归:找出大规模问题与小规模问题的关系,这样通过递归使问题的规模逐渐变小。
(2)设置边界、控制递归:找出停止条件,即算法可解的最小规模问题。
(3)设计函数、确定参数:设计函数体中的操作及相关参数。
ps:
递归:大规模问题逐级调用小规模问题的过程。
回溯:小规模问题逐层向上返回的过程。
二、题型总结
1、求两数的最小公倍数
输入两个正整数,求最小公倍数。
说明:该题目涉及到欧几里得算法,可以定义普通的函数,也可以用递归的方法来实现。
(1)普通算法:
#include<bits/stdc++.h>
using namespace std;
int common(int x,int y)
{
int r,x1,y1,a;
x1=x;
y1=y;
r=x%y;
while(r!=0)
{
x=y;
y=r;
r=x%y;
}
a=x1/y*y1;
return a;
}
int main()
{
int m,n;
cin>>m>>n;
cout<<common(m,n)<<endl;
return 0;
}
(2)递归算法:
int GCD(m,n)
{
if(n==0) return m;//边界条件
else return GCD(n,m mod n);
}
2.一个整数有几个奇数字,几个偶数字
题目描述:输入一个整数,判断它含有几个奇数字和几个偶数字。
思路:这个题目应该考虑一些细节问题,比如该整数为零的时候,应该单独提出来分析一下。可以定义两个函数,分别寻找奇数字和偶数字。
#include<cstdio>
#include<iostream>
using namespace std;
int find1(int x)
{
int y=0;
if(x%2==0||x==0)y++;
return y;
}
int find2(int x)
{
int y=0;
if(x%2!=0)y++;
return y;
}
int main()
{
long n,s1=0,s2=0;
cin>>n;
int i;
while(n!=0)
{
i=n%10;
s1+=find1(i);
s2+=find2(i);
n/=10;
}
cout<<s2<<endl<<s1;
return 0;
}
3.分解因数
题目描述:给出一个正整数a,要求分解成若干个正整数的乘积,即a = a1 * a2 * a3 * ... * an,并且1 < a1 <= a2 <= a3 <= ... <= an,问这样的分解的种数有多少。注意到a = a也是一种分解。
输入:第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a (1 < a < 32768)
输出:n行,每行输出对应一个输入。输出应是一个正整数,指明满足要求的分解的种数
分析:本题是典型的递归问题,通过寻找大规模问题和小规模问题之间的关系不难得出公式count(i,b/i),再找出递归边界i>b/i即可解决该问题。
#include<bits/stdc++.h>
using namespace std;
int sum;
int count(int a,int b)
{
for(int i=a;i<b;i++)
{
if(b%i==0&&i<=b/i)
{
sum++;
count(i,b/i);
}
if(i>b/i) break;
}
}
int main()
{
int n;
int a;
cin>>n;
while(n--)
{
sum=1;
cin>>a;
count(2,a);
cout<<sum<<endl;
}
return 0;
}