经过这近一个月的对函数的学习,我对函数的使用有了一定的认识。
一、函数的定义
1.函数的数据类型是函数的返回值类型(若数据类型为void,则无返回值)。在我理解中:函数是个不在主函数中,但是如果主函数需要他时,可以随时调用它。
2.形参表可以是空的(无参函数),也可以有多个形参,形参之间用逗号隔开,不管有无参数,函数名后的圆括号都必须有。形参必须有类型说明,形参可以是变量名,数组名或指针名,它的作用是实现主调函数与被调函数之间的关系。
3.函数不允许嵌套定义。在一个函数定义另一个函数是非法的,但是允许嵌套使用。
二、举例
定义一个函数,返回两个数中的较大值。
int max(int x,int y)
{
return x>y?x:y;
}
该函数表示返回整数,返回接受的两个实参中大的那一个。
三、函数的声明与调用
1.声明:类型说明符 被调函数名(含类型说明的形参表);例:int js(int n);也可以int js(int);
2.调用:函数名(实参列表) //例:sum+=js(i);
3.返回值:return(表达式); //例如return s;
四、传值调用
1.传值调用:方向是从实参到形参。简称单向值传递
2.传址调用:将实参变量的地址值传递给形参,这里的形参是指针!!
例:void swap(int &a,int &b)//传引用方式(相当于起别名)
{
int temp=a;a=b;b=temp;
}
int main()
{
int c=1,d=2;
swap(c,d)
}//swap函数的参数为传址调用,&a是指实参变量的地址值传递给形参。所以a,b的值相当于在主函数main中修改c,d的值。
五、指针
在说明变量时,前加“*”定义指针变量;前加&代表引用。(一般形式:类型标识符 *变量名:int *i point,*j point)
正常语句中用&代表取地址。
递归
1.定义:在函数中,其内部操作又直接或间接地出现对自身的调用,则称这种自己调用自己的程序嵌套定义为递归。
注:写递归时,一定要有终止条件。
例题:用递归求m,n的最大公约数
1.求m除以n的余数
2.如果余数不为零,则让m=n,n=余数,重复步骤1,即调用子函数
3.如果余数为零,则终止调用子程序。
程序如下:
#include<bits/stdc++.h>
using namespace std;
int gcd(int,int);
int main()
{
int m,n;
cin>>m>>n;
cout<<gcd(m,n)<<endl;
return 0;
}
int gcd(int m,int n)
{
return n==0?m:gcd(n,m%n);
}
简单来说,递归的本质就是自己调用自己,用调用自己的方法解决问题。
而能用递归解决的问题一般满足:1.需要求解的问题可以化为子问题求解,其子问题的求解方法与原问题相同。
2.递归调用的次数是有限的;必须有递归结束的条件。
心得:
自从学习完函数之后,再也不需要一串代码写到底了,完全可以把一个问题划分成好几个的小问题,分步解决,最后直接在主函数中调用解决。大大的提高了代码的可读性,同样也减少了代码的出错概率。在修改方面同样也轻松了不少。可以直接找到函数的问题并解决。
递归算法在我看来是到现在为止学过的最不好理解的算法,通俗来讲就是自己调用自己,但是怎样调用,怎样找出与原问题相同的小问题并将他的解决方法写出,还是我需要继续思考的问题。有些递归函数的写法也有所不懂。
例如这个放苹果的问题。需要考虑各种可能的情况。
#include<bits/stdc++.h>
using namespace std;
int f(int m,int n)
{
if(n==1||m==0)
{
return 1;
//如果只有一个盘子或者没有苹果只有一种放法。
}
if(n>m)
{
return f(m,m);
//盘子数目大于苹果数目,有多少个苹果就有多少种放法。
}
return f(m,n-1)+f(m-n,n);
//如果n<=m时,1.至少有一个盘子空着:f(m,n)=f(m,n-1);
//2.所有盘子都有苹果:从每个盘子里边拿走一个,不影响不同放法的数目。
//f(m,n)=f(m-n,n)。最后两种之和。
}
int main()
{
int t;
int m,n;
cin>>t;
for(int i=0;i<t;++i)
{
cin>>m>>n;
cout<<f(m,n)<<endl;
}
return 0;
}
对于递归的练习还应该加强,重要的是考虑好所有的解决方案。