`
tuhaitao
  • 浏览: 378830 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

递归算法优化

阅读更多
    那天闲来无聊,突然从网上看到一google面试题,比较有意思,于是整理了下先写下来,算法大概是这样的:
    T(0) = T(1) = 1;
    T(2) = 2;
    T(N) = T(N-1) + T(N-2) + T(N-3);
    算法前提不考虑溢出,于是我写下了最常规的递归算法:
public class Tribonacci {
    public static int method(int n) {
        if( 0 == n || 1 == n) {
            return 1;
        } else if( 2 == n) {
            return 2;
        } else {
            return method(n - 1) + method(n - 2) + method(n - 3);
        }
    }
}

    但是仔细琢磨了下,当n >= 3 事, 条件进入最后的else,这里其实进行了多次递归,其中 在递归n-1的时候其实已经计算出了n-2、n-3, 所以这个算发,很显然重复计算了后便的method(n-2)、method(n-3),所以这里可以在计算method(n-1)的时候记住n-2、与n-3的值,百般思索后写出了如下的程序:
public class Tribonacci {
    public static int method2(int n) {
        if( n < 0) {
            return 0;
        }
        if( 0 == n || 1 == n ) {
            return 1;
        }
        if( 2 == n ) {
            return 2;
        }
        ReferenceInt mid = new ReferenceInt();
        ReferenceInt last = new ReferenceInt();
		
        int max_subset = sub_recursion( n, mid, last);
        return max_subset + mid.getValue() + last.getValue();
    }

    public static int sub_recursion(int n, ReferenceInt mid, ReferenceInt last) {
        if ( 3 == n ) {
            mid.setValue(1);
            last.setValue(1);
            return 2;
        } else {
            ReferenceInt temp = new ReferenceInt();
            //这里做了参数移位,原来的last变为n-1的mid, 启用新的变量带出n-1的last
            mid.setValue(sub_recursion( n - 1, last, temp));
            return mid.getValue() + last.getValue() + temp.getValue();
        }
    }

    /**
     * 由于Java讨厌的自动封包机制,这里自己定义一个int的包装类型
     */
    class ReferenceInt {
        private int value;
	
	public ReferenceInt(int value) {
		this.value = value;
	}
	
	public ReferenceInt() {
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
	
	public String toString() {
		return String.valueOf(this.value);
	}
    }
}

    算法的思想就是在计算n-1的时候,用参数带出n-2与n-3的值,去掉重复的计算,减少递归的次数,达到优化算法的效果,这里我简单说一下:
    T(N) = T(N-1) + T(N-2) + T(N-3);
          mas_sub    mid     last
    话说一个哥们,用list来缓存n-2 -> 0 之间的结果,随说有点吃内存,不过看起来比上边这个算法,好看多了,呵呵,都说是G内存的时代了,我一听乐了,不过也算是懒人有懒办法吧,贴出来大家看下:
public class Tribonacci {
    public static List<Integer> list = new ArrayList<Integer>();
    static {
        list.add(1);
        list.add(1);
        list.add(2);
    }
    public static int method3(int n) {
        if(n<list.size()){
            return list.get(n).intValue();
        }else{
            for(int i=list.size();i<=n;i++){
                list.add(method3(i - 1) + method3(i - 2) + method3(i - 3));
            }
            return method3(n);
        }
    }
}

呵呵,下边测试一下3个算法的性能吧:
public class Tribonacci {
    public static void main(String[] args) {
        final int TEST_NUMBER = 35;
        long start = System.currentTimeMillis();
        System.out.print(Tribonacci.method1(TEST_NUMBER));
        long end = System.currentTimeMillis();
	System.out.println("->method1(" + TEST_NUMBER + ") cost:" + (end-start) + "ms");
	start = System.currentTimeMillis();
        System.out.print(Tribonacci.method2(TEST_NUMBER));
        end = System.currentTimeMillis();
	System.out.println("->method2(" + TEST_NUMBER + ") cost:" + (end-start) + "ms");
	
        start = System.currentTimeMillis();
	System.out.print(Tribonacci.method3(TEST_NUMBER));
	end = System.currentTimeMillis();
	System.out.println("->method3(" + TEST_NUMBER + ") cost:" + (end-start) + "ms");
    }
}

1132436852->method1(35) cost:10468ms
1132436852->method2(35) cost:0ms
1132436852->method3(35) cost:0ms
0
0
分享到:
评论
1 楼 linYuanSen 2012-09-05  
我自己的想法是,直接从头开始计算,到n为止。
public class Test {
	private static int iMax;//T(n-1)  max
	private static int iMid;//T(n-2)  mid
	private static int iLast;//T(n-3)  last
	
	public static void main(String[] args){
		System.out.println("T(0) " + fn(0) +"  T(1) " + fn(1) + "  T(2) " +fn(2));
		
		long start, end;
		 start = System.currentTimeMillis();  
	      System.out.println("fn36 : " + fn(35));  
	     end = System.currentTimeMillis();  
		System.out.println("pay times: " + (end - start) + "ms.");
		
	}
	
	
	public static int fn(int n){
		if(n < 3){
			return ((0==n || 1==n) ? 1 : 2);
		}else{
			init();
			int times = (int) Math.rint(n/3);//下面运算次数
			
			while(0 != times){
				iLast = iMax + iMid + iLast;//T(n-3) = T(n-4) + T(n-5) + T(n-6)
				iMid = iMax + iMid + iLast;//T(n-2) = T(n-4) + T(n-5) + T(n-3)
				iMax = iMax + iMid + iLast;//T(n-1) = T(n-4) + T(n-2) + T(n-3)
				times--;
			}
			
			int result = -1;
			if(0 == n % 3) result = iLast;
			if(1 == n % 3) result = iMid;
			if(2 == n % 3) result = iMax;
			
			return result;
		}
	}
	
	public static void init(){
		iMax = 2;
		iMid = 1;
		iLast = 1;
	}

}

相关推荐

    .net递归算法优化源码案例

    本篇文章将深入探讨.NET中如何进行递归算法的优化,以及提供相关的源码案例。 一、理解递归 递归算法的基本思想是函数在执行过程中调用自身,每次调用都会创建一个新的函数调用栈帧。递归通常包含两个关键部分:...

    .net 递归算法 .net 递归算法.net 递归算法

    在.NET编程环境中,递归算法是一种强大的工具,它允许函数或方法调用自身来解决复杂问题。递归的核心思想是将大问题分解为相同或相似的小问题,直到问题变得足够简单,可以直接得出答案。这种解决问题的方式在数据...

    acm递归算法总结竞赛

    7. **动态规划与记忆化**:为了优化递归算法,可以采用动态规划的思想,将已经计算过的子问题结果存储起来,避免重复计算,这种方法称为记忆化搜索。 8. **递归与分治策略**:递归往往是分治算法的实现方式,如快速...

    合并排序递归和非递归算法

    3. **可读性和实现难度**:递归算法通常代码简洁,易于理解,而非递归算法可能需要更复杂的逻辑来模拟递归行为。 总的来说,选择哪种实现方式取决于具体场景,如内存限制、性能要求以及代码的可读性等。递归版本的...

    程序设计中递归算法

    ### 递归算法在程序设计中的应用 #### 一、递归的概念与本质 递归是一种重要的编程思想,在计算机科学和数学领域都有广泛的应用。它指的是一个过程或函数直接或间接地调用自身来解决问题的方法。递归的核心在于将...

    递归算法专题ppt

    ### 递归算法专题知识点详解 #### 一、递归算法原理 递归算法是一种将问题分解成子问题的方法,其中子问题与原问题性质相同但规模较小。递归算法的关键在于识别出能够通过递归解决的问题,并找到递归的基本情况...

    中序遍历二叉树非递归算法

    在IT领域,尤其是在数据结构与算法的学习中,中序遍历二叉树的非递归算法是一个关键且实用的知识点。通常,我们首先通过递归来实现二叉树的遍历,但递归方法可能因深度过大导致栈溢出,因此掌握非递归版本的遍历算法...

    递归算法到非递归算法的转换.ppt

    然而,在某些场景下,非递归算法可能更有利于性能优化或理解。本章将探讨如何将递归算法转换为非递归算法。 首先,我们要了解递归的定义。递归发生在一个过程或函数在定义中调用自身,这被称为直接递归。如果一个...

    背包问题递归算法C语言

    **背包问题递归算法在C语言中的实现** 背包问题是一个经典的计算机科学问题,它涉及到在给定容量限制的背包中,如何选择物品以达到最大的价值。这个问题通常被用来模拟资源有限的情况下的决策优化,比如投资组合...

    简单的递归算法

    3. **尾递归优化**:在某些语言中,如Scala或Haskell,可以利用尾递归特性来优化递归算法,使得其运行效率接近于循环。 4. **数学公式**:对于斐波那契数列,存在闭合形式的解,即著名的Binet公式,虽然在实际编程...

    关于递归算法时间复杂度分析的探讨.pdf

    关于递归算法时间复杂度分析的探讨,是一个深入理解算法效率和优化的关键议题。递归,作为解决问题的一种强大工具,其本质是将复杂问题分解为更简单的子问题,通过求解这些子问题来达到最终解决方案的目的。然而,...

    阿克曼函数 c程序 递归与非递归算法的综合

    在这个压缩包中,你将找到两个关于阿克曼函数的C语言实现:一个使用了递归算法,另一个则通过栈来模拟递归。 首先,让我们深入理解阿克曼函数。它通常定义为A(m, n),其中m和n是正整数。阿克曼函数的计算规则如下:...

    易语言递归算法求阶乘

    在编程领域,递归算法是一种基于函数自我调用的解决问题的方法。它通常用于解决那些可以被简化为相同问题子集的问题。"易语言"是中国的一种简单易学的编程语言,旨在降低编程难度,让更多人能接触编程。在这个场景中...

    Python基于递归算法实现的走迷宫问题

    ### Python基于递归算法实现的走迷宫问题详解 #### 一、递归算法简介 在探讨如何使用Python实现走迷宫问题...同时,也需要注意递归算法可能带来的性能问题,适时采取优化措施,如尾递归优化或者使用迭代方法替代。

    用递归算法实现两个整数最大公约数的计算

    然而,递归算法也有其局限性,如过度的递归调用可能导致栈溢出等问题,因此在实际应用中需注意控制递归深度和优化算法效率。 总之,理解递归算法以及如何在具体问题中运用它,是程序员和算法设计师必备的技能之一。...

    Hanoi塔问题非递归算法的形式推导

    ### Hanoi塔问题非递归算法的形式推导 #### 一、引言 Hanoi塔问题,也称为汉诺塔问题,是一个...这种非递归算法不仅适用于Hanoi塔问题,其思想还可以应用于其他类似的递归问题,为优化递归算法提供了一个新的视角。

    递归算法算斐波那契数列

    ### 递归算法计算斐波那契数列 #### 知识点概览 1. **斐波那契数列定义** 2. **递归算法原理** 3. **递归函数设计** 4. **递归算法的时间复杂度分析** 5. **C语言实现递归斐波那契数列** #### 斐波那契数列定义 ...

    C#递归算法经典示例

    在编程领域,递归算法是一种强大的工具,尤其在处理具有层次结构的问题时。在C#中,递归常被用于解决复杂的数据结构问题,如树形结构的遍历。本篇我们将深入探讨“C#递归算法经典示例”,特别关注如何使用递归算法...

    二叉树遍历的非递归算法分析与实现

    ### 二叉树遍历的非递归算法分析与实现 #### 一、引言 在数据结构领域中,二叉树作为一种基本的数据组织形式,其应用极为广泛。对于二叉树的操作,其中最重要的就是遍历操作。遍历是指按照特定顺序访问二叉树的...

    汉诺塔非递归算法实验报告

    实验的结论部分可能总结了非递归算法的效率和适用性,并可能讨论了进一步的优化或改进方向,比如如何更有效地实现盘子的移动,或者如何扩展算法以适应更大的盘子数量。 附带的源代码中定义了一个结构体`dish`来存储...

Global site tag (gtag.js) - Google Analytics