我的递归思路。

算法可以说是计算机里的数学,也可以描述成带有计算机特点的数学。我把递归视为一种特别的函数。用数学的思想来思考递归更加明晰快速。

看一个经常见到的例子,累加1+2+3+4+···········+n。

数学表达式为:

代码形式为:

	public  int Sum(int n)
	{
	    if(n==1) {return 1;}
	    else {return n+Sum(n-1);}
	}

这是我们常见的形式,递归出口为: n>1。递归体为: f(n-1)+n。这是一个出口,思考一下,数值为1,2,4,5,,,n,既然n>1可以作为出口 ,数值小于n是否同样可行呢。累加换一种更加普遍问法,n,n+1,n+2,n+3,n+4,,,+m-1,m

这样边界更加清晰。

数学表达式为:

把小的那头作为递归出口。

把大的那头作为递归出口。

代码写出来:

	public  int Sum(int start, int end)
	{
	      if(end==start)  {return start;}
	      else {return end+Sum(start,end-1);}
	}
	public int Sum(int start ,int end)
	{
	    if(start<end) return start+ Sum(start+1,end);
	    else    return end;
	}

代码按顺序对应。

在看另一个经典范例,斐波那契数列:1,1,2,3,5,8,13,21..........。数学描述为

代码描述为:

	public int fib(int n)
	{
	    if(n==1) return 1;
	    if(n==2) return 1;
	    return fib(n-1)+fib(n-2);
	}

十分明显的对应关系。用数学表达式也很容易描述。然而现实的递归,往往递归体比较复杂,不像例子中的单线递归。多路递归就相当麻烦了。

比如归并排序。二路归并情况下代码

   private  void MergeSortFunction(int[] array, int first, int last)
        {
                if (first < last)  
                {
                    int mid = (first + last) / 2;  
                    MergeSortFunction(array, first, mid);   //对划分出来的左侧子表进行递归划分
                    MergeSortFunction(array, mid + 1, last);    //对划分出来的右侧子表进行递归划分
                    MergeSortCore(array, first, mid, last); //对左右子表进行有序的整合(归并排序的核心部分)
                }
        }

数学描述有些困难,需要动用积分函数的知识,脑补了。二路归并的思路是,层层分割,知道分割成一个个的单元,然后层层配对合并排序,直到最后完成。递归出口是最小单元(即各个数值元素),表现出来就是first=last,无可分割,递归体在递归到出口后一层层返回的过程中一层层排序,直到最后排序完成。

当遇到个问题可分割,分割的结果又存在相似性,有明确的边界条件,并且分割的上一层级对下一层级具有依赖性,就可以考虑递归的使用,仔细考虑,递归边界,边界内的代码,边界外的代码三部分。考虑成熟了,代码也差不多出来了。

时间: 2024-08-09 10:44:53

我的递归思路。的相关文章

汉诺塔问题递归与非递归思路

//递归解法,复杂度为O(2^n)//T(n) = 2(n-1) + 1//T(1) = 1#include <iostream> using namespace std; void hanoi(int n, char a, char b, char c) { if (n==1) cout << n << " " << a << " " << c << endl; else { ha

用两种递归思路与循环实现单链表的反转

typedef struct ListNode{ int data; struct ListNode *next; }ListNode; //递归一 ListNode *ReverseList (ListNode *pHead, ListNode *nHead = NULL) { //每次取下第一个节点头插法创建新链表 //nHead为反转后链表的头节点 if(pHead == NULL) return NULL; ListNode *pNext = pHead -> next; pHead -

约瑟夫环(猴子问题)递归思路解法

“约瑟夫环”是一个数学的应用问题:一群猴子排成一圈,按1,2,…,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数, 再数到第m只,在把它踢出去…,如此不停的进行下去, 直到最后只剩下一只猴子为止,那只猴子就叫做大王.要求编程模拟此过程,输入max.size, 输出最后那个大王的编号. 对于这个问题,可以这么解:每次有猴子出列后,就给所有猴子重新编号:首先第一个出列的猴子编号NO1=(size % max)==0 ? max : (size % max)(作判断是因为si

递归思路

需求:计算1*2*3*....*1000的值 常规代码: def func(arg): res = 1 for i in range(1, arg): res *= i return res 递归方法: def fun(arg): if arg == 1: return 1 return arg*(fun(arg-1)) 通过此函数发现,函数最终return的是函数本身的表达式,如果计算5以内的阶乘,他的运行如下: fun(5)调用函数fun()函数,此时arg = 5,5>1,所以会retur

递归思路简单例子

var a = 0; function fun(i) { a++; console.log(a); fun(i+1); console.log("end"); } fun(0); //调用自己 运行结果如下,陷入死循环,永远不会执行console.log("end")直至程序报错 给了条件之后 ,当条件满足然后他就开始返回 var a = 0; function fun(i) { if(i >50) {//不给条件的话他会一直陷入死循环直至程序报错 retur

八皇后问题,递归法实现

八皇后问题,是19世纪著名的数学家高斯在1850年提出的:在8×8格的国际象棋盘上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列.同一斜线上,试问有多少种摆法?高斯先生给出的答案是“76”种,实际是76种吗? 八皇后问题是回溯算法的典型应用,但是本文提供递归的求法. 递归的核心思想可以总结成:把一个复杂的问题无限缩小,每个小问题的解法都是一样的,最终归结于求解每个小问题的原型.递归编程的思路可以假设所有的问题都已解决,来到结束条件,这是非常简单的,然后再调用自身求解整个问

POJ-1163-The Triangle: DP入门 递归 递推

递归思路 超时算法 #include<iostream> using namespace std; #define Size 101 int Triangle[Size][Size]; int n; int GetAns( int i, int j ) { if( i==n ) return Triangle[i][j]; int x=GetAns( i+1, j ); int y=GetAns( i+1, j+1 ); return max(x, y)+Triangle[i][j]; } i

递归入门 Java

对于强大的递归.要想做到灵活运用,是需要花时间进行练习并总结.往往递归学习的入门也是难度也比较大,常常会处于看得明,却写不出的"尴尬"情况. 递归的定义 将一个大的问题分解成比较小的.有着相同形式的问题. 递归是一种强有力的思想.在计算机科学的学习中,一个重要的必须学习的概念是递归.递归是一种编程策略,它把一个大的问题分解成具有相同形式的简单问题. 使用递归的必需条件 可以通过递归调用来缩小问题规模,且新问题与原问题有着相同的形式 存在一种简单情境,可以使递归在简单情境下退出 一般对递

C语言强化(十一)二叉树镜像变化 | 要求:不使用递归

用了这么久的递归,现在不让用递归了,你行么? 通过这道题,你可以学会 如何镜像变化一棵二叉树 什么是递归的本质 如何巧妙地使用辅助栈 题目: 输入一颗二元查找树,将该树转换为它的镜像, 即在转换后的二元查找树中,左子树的结点都大于右子树的结点. 要求: 不使用递归 例如输入: 输出: 将二叉树镜像变化的方法很简单,只要把所有节点的左右节点对调就行了,使用递归可以非常容易的实现. 如下为递归方法实现镜像变化的函数 /** 二叉树镜像变化--递归方法实现 */ void Revertsetree_R