递归调用学习笔记

        所谓函数的递归调用是指在调用一个函数的过程中出现直接或间接调用该函数自身的情况。例如,在调用f1()函数的过程中,又调用了f1()函数,这称为直接递归调用;而在调用f1()函数的过程中,调用了f2()函数,又在调用了f2()函数的过程中调用了f1()函数,这称为间接递归调用。

       提到递归调用,最常用的例子就是求一个正整数的阶乘问题。例如,求整数5的阶乘,即5!。由于5!=5*4!,4!=4*3!,… 1!=1*0!,而0!等于1是已知的。于是可求出5!=5*4*3*2*1*1等于120。

由此可见,使用递归调用解决问题的方法如下:

原有的问题能够分解为一个新的问题,而新的问题有用到了原有问题的解法,这就出现了递归。按这一原则分解下去,每次出现的新问题是原问题简化后的子问题,最终分解出来的新问题是一个已知解的问题。这便是递归调用。

一、递归调用的过程

递归调用可分为两个阶段:

  1. “递推”阶段:将原问题不断分解为新的子问题,逐渐从未知向已知的方向推测,最终到达已知的条件,即递归结束条件,这是递推阶段结束。
  2. “回归”阶段:该阶段是从已知的条件出发,按照“递推”的逆过程,逐一求值回归,最后到达递推的开始处,结束回归阶段,完成递归调用。

二、递归调用的特点

(1)  递归调用方法编写程序简洁清晰,可读性强;

(2)  递归调用在时间和空间的开销上比较大,既要花费较长的计算时间,又要占用较多的内存单元。

三、递归调用实例

(1)   求阶乘

(2)   求前n项的和

(3)   Fibonacci函数

(4)  汉诺塔问题

(5)  二叉树遍历

(6)  二叉树的所有路径

             ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

             1.求阶乘代码:

#include"iostream"
using namespace std;

long int fac(int n);
int main(){
  int n;
  cout<<"Input a positive integer:"<<endl;
  cin>>n;
  long fa=fac(n);
  cout<<n<<"!="<<fa<<endl;
   system("pause");
   return 0;
}

long int fac(int n){
	 long int p;
	 if(n==0) p=1;
	 else p=n*fac(n-1);
	 return p;
}
(2)求前n项的和代码(1+2+3+4+5+6....)
#include"iostream"
using namespace std;

class Recursion {  
public:
	Recursion(int x,int y):sum(x),a(y){}
	void add(){  
	   sum+=a; a++;  
	   if(a<=5) {  
		add();//调用自身实现递归  
	   } 
	}
public:
	int sum;  
	int a; 
};  

int main() {  
     Recursion T(0,1);

	 T.add();
	 cout<<"sum="<<T.sum<<endl;
	 system("pause");
	 return 0;
}  

(3)   Fibonacci函数(斐波那契数列)

斐波那契数列是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …

第1项是0,第2项是第一个1,这个数列从第3项开始,每一项都等于前两项之和。

        Fibonacci函数的数学表达式为:

 
                                                       
         Fibonacci函数代码:

#include"iostream"
using namespace std;
 
long int Fib(int n){
	if(n==1) return 0;
	else if(n==2)return 1;
	else return Fib(n-1)+ Fib(n-2);
}

int main() { 
	int n;
    cout<<"Input a positive integer:";
    cin>>n;
    long int f=Fib( n);
	cout<<"Fib("<< n<<")="<<f<<endl;
	system("pause");
	return 0;
} 

(4)  汉诺塔问题

有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:

(1)每次只能移动一个圆盘;

(2)大盘不能叠在小盘上面。

注:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。


      汉诺塔问题代码
#include <iostream>
#include <cstdio>
using namespace std;
int T=0; //移动的次数
void hannoi (int n, char from, char buffer, char to){
    if (n == 1){
        cout << "Move disk " << n << " from " << from << " to " << to << endl;
	    T++;
	}
    else{
        hannoi (n-1, from, to, buffer);
        cout << "Move disk " << n << " from " << from << " to " << to << endl;
		T++;
        hannoi (n-1, buffer, from, to);
    }
}
 
int main()
{
    int n;
	cout<<"输入圆盘的个数:";
    cin >> n;
    hannoi (n, 'A', 'B', 'C');
	cout<<"移动的次数:"<<T<<endl;
	system("pause");
    return 0;
} 

(5)  二叉树遍历

二叉树有3个基本组成单元:根节点(D)、左子书(L)、右子树(R)。二叉树的遍历分为三种:前(先)序、中序、后序遍历。则先(根)序遍历二叉树的顺序是DLR,中(根)序遍历二叉树的顺序是LDR,后(根)序遍历二叉树的顺序是LRD。还有按层遍历二叉树。这些方法的时间复杂度都是O(n),n为结点个数。

         递归调用遍历二叉树代码:

#include <iostream>
#include <cstdio>
using namespace std;

struct node{
    int data;          //数据元素
    node *left,*right; //指向左子树、右子树
};
class Btree
{
   static int n;
   static int m;
public:
    node *root;
    Btree(){
        root=NULL;
    }
    void create_Btree(int);                 //构造二叉树
    void Preorder(node *);                  //先序遍历
    void inorder(node *);                   //中序遍历
    void Postorder(node *);                 //后序遍历
    void display1() {Preorder(root); cout<<endl;}
    void display2() {inorder(root);cout<<endl;}
    void display3() {Postorder(root); cout<<endl;}  
};  

int Btree::n=0;
int Btree::m=0;
void Btree::create_Btree(int x){
    node *newnode=new node;   //新建一个节点
    newnode->data=x;          //节点赋值  
    newnode->right=newnode->left=NULL;//并且新节点的左右子树为空
    if(root==NULL)     //根节点是否为空
        root=newnode;  //根节点是否为空时,根节点为newnode
    else{
        node *back;
        node *current=root; 
		//将大于根节点的值赋给右子树,小于根节点的数赋给左子树
        while(current!=NULL){
            back=current;
            if(current->data>x) 
                current=current->left;
            else
                current=current->right;
        }
        if(back->data>x)
            back->left=newnode;
        else
            back->right=newnode;
    }
}
void Btree::Preorder(node *temp)    //这是先序遍历二叉树,采用了递归的方法。
{
    if(temp!=NULL){
        cout<<temp->data<<" ";
        Preorder(temp->left);
        Preorder(temp->right);
    }
}
void Btree::inorder(node *temp)      //这是中序遍历二叉树,采用了递归的方法。
{
    if(temp!=NULL){
        inorder(temp->left);
        cout<<temp->data<<" ";
        inorder(temp->right);
    }
}
void Btree::Postorder(node *temp)     //这是后序遍历二叉树,采用了递归的方法。
{
    if(temp!=NULL){
        Postorder(temp->left);
        Postorder(temp->right);
        cout<<temp->data<<" ";
    }
}

void main()
{
    Btree A;
    int array[]={7,4,2,3,15,35,6,45,55,20,1,14,56,57,58};
    int k;
    k=sizeof(array)/sizeof(array[0]); //数组元素个数
    cout<<"建立排序二叉树顺序: "<<endl;
    for(int i=0;i<k;i++){
        cout<<array[i]<<" ";
        A.create_Btree(array[i]);
    }
    cout<<endl;
    cout<<endl<<"先序遍历序列: "<<endl;
    A.display1();
    cout<<endl<<"中序遍历序列: "<<endl;
    A.display2();
    cout<<endl<<"后序遍历序列: "<<endl;
    A.display3();
	system("pause");
}
程序中构造的二叉树如下图所示


(6)  二叉树的所有路径

当一个节点的左右子树都为空时,把从根节点到该节点的路径保存在向量中,找到所有的叶子节点就完成了对所有路径的保存.

二叉树所有路径代码:

#include <iostream>  
#include <cstdio>  
#include <stdio.h>
#include <vector> 
#include <string> 

using namespace std;

struct node {
	int data;          //数据元素  
	node *left, *right; //指向左子树、右子树
	node() {}
	node(int val) {
		this->data = val;
		this->left = this->right = NULL;
	}
};

class Btree
{
public:
	node *root;
	Btree() {
		root = NULL;
	}
	void create_Btree(int);                 //构造二叉树  
};

class PathsBtree {
public:
	/**
	* @param root the root of the binary tree
	* @return all root-to-leaf paths
	*/
	vector<string> binaryTreePaths(node* root) {
		vector<string>Paths;
		if (root == NULL) return Paths;
		bTreePathsCore(root, Paths, to_string(root->data));
		return Paths;
	}
	void bTreePathsCore(node *root, vector<string>&Paths, string strPaths)
	{
		if (root->left == NULL&&root->right == NULL) {
			Paths.push_back(strPaths);
			return;
		}
		if (root->left != NULL)
			bTreePathsCore(root->left, Paths, strPaths + "->" + to_string(root->left->data));
		if (root->right != NULL)
			bTreePathsCore(root->right, Paths, strPaths + "->" + to_string(root->right->data));
	}
};


void Btree::create_Btree(int x) {
	node *newnode = new node;   //新建一个节点  
	newnode->data = x;          //节点赋值    
	newnode->right = newnode->left = NULL;//并且新节点的左右子树为空  
	if (root == NULL)     //根节点是否为空  
		root = newnode;   //根节点是否为空时,根节点为newnode  
	else
	{
		node *back=NULL;
		node *current = root;
		//将大于根节点的值赋给右子树,小于根节点的数赋给左子树  
		while (current != NULL) 
		{
			back = current;
			if (current->data>x)
				current = current->left;
			else
				current = current->right;
		}
		if (back->data>x)
			back->left = newnode;
		else
			back->right = newnode;
	}
}

void main()
{
	Btree A;

	int array[] = { 7,4,2,3,15,35,6,45,55,20,1,14,56,57,58 };
	int k;
	k = sizeof(array) / sizeof(array[0]); //数组元素个数  

	cout << "建立排序二叉树顺序: " << endl;
	for (int i = 0; i<k; i++) {
		cout << array[i] << " ";
		A.create_Btree(array[i]);
	}

	PathsBtree pa;
	vector<string> path=pa.binaryTreePaths(A.root);

	for (int i = 0; i < path.size();i++) {
		cout <<"root-to-leaf path "<<(i+1)<<":"<< path.at(i) << endl;
	}

	system("pause");
}


参考资料:http://www.cnblogs.com/elleniou/archive/2012/05/03/2480042.html

               http://www.cricode.com/3489.html

              http://blog.csdn.net/fanglegefang/article/details/70477509


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值