C++函数及其应用
一.为什么要用函数
我们知道,c和c++中使用函数,能简化代码量,对各个部分进行封装,使得问题变得简单和直观,提高了程序的易读性。
还可以提升可维护性,把一些计算或操作编成通用的函数,以供随时调用,从而避免了代码的重复冗长。
但是运用函数,就需要传递参数,开辟缓存、堆栈等,相比较而言,会耗一些多余的效率。
例:比较三个数的大小
#include <iostream> using namespace std; void func(int a,int b,int c) { int middle,max,small; if(a>b){ max=a; middle =b; } else{ max=b; middle =a; } if(c>max){ cout << c << " " << max << " "<< middle; } else if(c<middle){ cout << max << " " << middle << " " <<c; } else{ cout << max << " " << c << " " <<middle; } } int main(){ int a,b,c; cout << "请输入a,b,c的大小\n"; cin >> a >> b >> c; func(a,b,c);//进行排序 return 0; }
??我们可以看出用一个func函数对三个数进行比较大小后,主函数就变得简单清晰,程序可读性变强。
二.函数重载
??在C++中,如果需要定义几个功能相似,而参数类型不同的函数,那么这样的几个函数可以使用相同的函数名,这就是“函数重载”。
两个重载函数必须在下列一个或两个方面有所区别,仅仅返回值类型不同是不行的。
1、函数的参数个数不同;
2、函数的参数类型不同或者参数类型顺序不同。
例如,求和函数,对应不同的参数类型,可以定义如下几个重载函数:
#include<iostream> using namespace std; int sum(int a=0,int b=0){ return a+b; } double sum(double a=0,double b=0){ return a+b; } float sum(float a=0,float b=0,float c=0){ return a+b+c; } int main(){ int x=sum(5,9); float y=sum(2.7,5.87); float z=sum(float(x),y,5); cout << x << " " << y << " " << z; return 0; }
三.什么是值传递
??调用时,将实参的值传递对应的形参,即为值传递。函数中对任何形参值得修改都不会改变实参变量的值。
例如经典的交换x,y的值:
#include<iostream> using namespace std; void swap(int x,int y){ int temp; temp=x; x=y; y=temp; cout << "swap中a和b " << x << " " << y << endl; } int main(){ int a,b; cin >> a >> b; swap(a,b); cout << "main中a和b " << a << " " << b << endl; return 0; }
??我们分析一下整个程序:在主函数中,实参a和b有自己的存储空间,并且有自己的初始值。当调用函数Swap时,内存给函数的参数x和y分配存储空间,并将a和b的值复制过来,函数执行过程中,将x和y的值进行交换,当函数执行结束之后,x和y所占用的存储空间将被释放,这种传递的方式,并不会对实参a和b的值产生影响,所以看到的a和b的值没哟改变。
四.什么是传引用
??引用变量是变量的另一个别名,它没有自己的存储数据的内存位置,它访问的是另一个变量的内存位置。对引用变量作出的任何更改,实际上都是对它所引用的变量内存位置中存储数据的更改。
我们用传值的程序,把void swap(int a,int b){...}改为void swap(int &a,int &b){...}。可以看出,在main函数中,ab的值发生了改变。
五.如何编写递归函数
??说起递归,不得不说他很想小时候听过的故事:从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山...
网上流传的这个表情包,他也很好的诠释了什么叫递归。递归的原理就是通过栈机制来把递归过程中的函数,以及它的符号入栈和出栈,并在出栈过程中对这些符号和函数返回值等进行运算。
??我们再来看看不好理解的汉罗塔问题:该问题是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置n个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。
??研究这个问题我们就要利用递归思想,要把n个盘子从A->C,我们就要先把n-1个盘子从A->C->B,再把A最后一个盘子从A->C,紧接着再把n-1个盘子从B->A->C上。
再具体一点,就是我们要把前n-2个盘子移动到B上,n-3个盘子移动到C上,以此类推,最终推出第一个盘子应该放在B或者C上。由于递归是倒序输出,我们在前面已经记录过倒数第二个盘子应放在哪里,再把前两个盘子叠加在一起,在记录中找出倒数第三个盘子放在哪里,以此类推,一直到n-1个盘子把他们叠在一起就完成了第一步(我们就要先把n-1个盘子从A->C->B),第一部move(n-1,x,z,y)递归函数调用彻底结束。
这时中间语句直接输出第n个盘子从A->C,完成第二部。
完成后到达第三个move函数, move(n-1,y,x,z),这个函数的作用和第一个函数的作用相似,只是改变了起始针,中间针和目的针。原理和第一个递归函数相同。由于我们知道第一个递归函数和第二个递归函数是相似的,步骤也是相同的,可以得出汉诺塔的步数一定是个奇数(加上中间直接移动最后一个盘子的一步)。
具体代码:
//栈之递归汉诺塔问题 #include<iostream> using namespace std; void move(int n,char x,char y,char z){ if(n==1) cout << x <<"->" << z << endl; //把x放到z上 else{ move(n-1,x,z,y); cout << x <<"->" << z << endl; move(n-1,y,x,z); } } int main(){ move(3,'x','y','z'); return 0; }