`

递归及其替代算法

 
阅读更多
import java.util.LinkedList;

import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MoveAction;

import com.sun.corba.se.spi.orbutil.fsm.State;
import com.sun.org.apache.xpath.internal.functions.Function;

/**
 * 递归算法,递归的非递归替代算法
 *
 */
public class TestRecursion
{
  // 题目:计算给定文本内字符“a”的个数。分别用迭代和递归两种方式。
  /**
   * 常规算法
   */
  public int countACommon(String str)
  {
    int count = 0;
    String tmpString = str;
    while (tmpString.indexOf("a") >= 0)
    {
      count++;
      tmpString = tmpString.substring(tmpString.indexOf("a") + 1);
    }
    return count;
  }

  /**
   * 递归算法
   */
  public int countARecursion(String str)
  {
    String tmpStr = str;
    if (tmpStr.indexOf("a") < 0) return 0; // 递归退出条件
    else return countARecursion(tmpStr.substring(tmpStr.indexOf("a") + 1)) + 1;

  }

  /**
   * 斐波那契数列 项,非递归(速度快,求第10000项毫无压力)
   */
  public int f(int n)
  {
    if (n < 1) return 0;
    if (n == 1) return 1;
    if (n == 2) return 1;

    int i, s = 0;
    int s1 = 1, s2 = 1;
    for (i = 3; i <= n; i++)
    {
      s = s1 + s2;
      s2 = s1;
      s1 = s;
    }
    return s;
  }

  /**
   * 单向递归是指递归算法中虽然有多处递归调用语句,
   * 但各递归调用语句的参数之间没有关系,
   * 并且这些递归调用语句都处在递归算法的最后。显然,尾递归是单向递归的特例。
   * 斐波那契数列 项,递归(求第100项时就扛不住了)
   * 1 1 2 3 5 8 13
   */
  public int f2(int n)
  {
    if (n < 1) return 0;
    if (n == 1) return 1;
    if (n == 2) return 1;

    return f2(n - 2) + f2(n - 1);
  }

  /**
   * 求阶乘,非递归,最大求31,超过31!,int就不够用了
   * @param n
   * @return
   */
  public int factorial(int n)
  {
    if (n < 0) return 0;
    if (n == 0) return 1;
    if (n == 0) return 1;
    int s = 1;
    for (int i = 1; i <= n; i++)
    {
      s = s * i;
    }
    return s;
  }

  /**
   * 求阶乘,递归算法,最大求31,超过31!,int就不够用了
   * @param n
   * @return
   */
  public int factorial_R(int n)
  {
    if (n < 0) return 0;
    if (n == 0) return 1;
    if (n == 0) return 1;
    return n * factorial_R(n - 1);
  }

  /**
   * 汉诺塔,递归算法(将A上面的盘子,借助B,移动到C上面)
   * @param n 需要移动的盘子个数
   * @param A 盘子所在的原始位置
   * @param C 盘子的目标位置
   * @param B 移动盘子借助的位置
   */
  public void hanoi_R(int n, String A, String B, String C)
  {
    if(n == 1) move(n,A,C); //只有一个盘子,直接移
    else 
    {
      hanoi(n - 1,A,C,B); // 先将n-1个盘子,从A移动到B,借助C
      move(n,A,C);        //将最后一个盘子 直接 从A移动到目标位置C,此时A空下来,B上面有n-1个盘子
      hanoi(n-1,B,A,C);   //将B上面的n-1个盘子,借助A,移动到C
    }
  }

  private void move(int n,String from ,String to)
  {
    //System.out.println("move " + n + ": " + from + " --> " + to);
  }
  
  
  /**
   * 非递归算法,使用栈,HanoiItem栈对象,以保存相关中间信息
   */
  class HanoiItem
  {
    public int count;                 //可以直接移动的盘子的编号
    public boolean flag = false;      //flag = true 说明可以直接移动
    public String currentPlace;       //当前位置
    public String assistantPlace;     //辅助位置
    public String destinationPlace;   //目标位置
    
    public HanoiItem(int count,boolean flag,String currentPlace,String assistantPlace,String destinationPlace)
    {
      this.count = count;
      this.flag = flag; //只有一个盘子表示可以直接移动
      if(count==1) this.flag = true; //重要: 如果只有一个盘子,表示可以直接移动
      this.currentPlace = currentPlace;
      this.assistantPlace = assistantPlace;
      this.destinationPlace = destinationPlace;
    }
    
    public void move()
    {
      //System.out.println("move " + this.count + ": " + currentPlace + " --> " + destinationPlace);
    }
  }
  
  /**
   * 将初始状态s0进栈
   * while (栈不为空)
   * {
   *    退栈,将栈顶元素赋给s;
   *    if (s是要找的结果) 返回;
   *    else 
   *    {
   *      寻找到s的相关状态s1;
   *      将s1进栈;
   *    }
   * }
   * 
   */
  
  public void hanoi(int n, String A, String B, String C)
  {
    if(n == 1) move(n,A,C); //只有一个盘子,直接移
    else 
    {
      //初始化一个栈,LinkedList可以当栈使用
      LinkedList<HanoiItem> stack = new LinkedList<HanoiItem>();
      HanoiItem initHanoi = new HanoiItem(n, false, A, B, C);
      stack.push(initHanoi);  //将初始状态s0进栈
      
      while(stack.size()>0) //while (栈不为空)
      {
        HanoiItem tempItem = stack.pop(); //退栈,将栈顶元素赋给s;
        if(tempItem.flag) //if (s是要找的结果) 返回;
        {
          tempItem.move();
        }
        else  //寻找到s的相关状态s1; 这里相关的状态有三个
        {
          //表示需要将上面的n-1个盘子 借助于 目标位置 ,整体先移动到 中间(协助用)的 杆子
          HanoiItem ItemBefore = new HanoiItem(tempItem.count - 1,false,tempItem.currentPlace,tempItem.destinationPlace,tempItem.assistantPlace);
          //表示将最后一个盘子移动到目标位置
          HanoiItem itemCurr = new HanoiItem(tempItem.count,true,tempItem.currentPlace,tempItem.assistantPlace,tempItem.destinationPlace);
          //表示将 前面已经移动到中间杆子上的盘子,借助第一个杆子 移动到 目标位置
          HanoiItem itemAfter = new HanoiItem(tempItem.count -1,false,tempItem.assistantPlace,tempItem.currentPlace,tempItem.destinationPlace);
          
          //将上面三个中间状态入栈,注意顺序,栈先进后出,所以入栈顺序要反过来
          stack.push(itemAfter);
          stack.push(itemCurr);
          stack.push(ItemBefore);
        }
      }
    }
  }

  public static void main(String[] args)
  {
    String tmpString = "aaa";
    TestRecursion test = new TestRecursion();
    System.out.println(test.countACommon(tmpString));
    System.out.println(test.countARecursion(tmpString));
    System.out.println(test.factorial_R(5));
    
    //递归汉诺塔
    long s1 = System.currentTimeMillis();
    test.hanoi_R(15,"A","B","C");
    long e1 = System.currentTimeMillis();
    System.out.println(e1 - s1); //移动,10层,0,15层 16, 20层,140,25层 3547, 30层 112830
    
    //非递归
    System.out.println("-----------------------------------");
    long s2 = System.currentTimeMillis();
    test.hanoi(15,"A","B","C");
    long e2 = System.currentTimeMillis();
    System.out.println(e2 - s2); 
    //移动10层 16, 15层 16, 20层 110,25层 3453,30层 114596,
    //貌似因为递归使用了太多的中间对象,而且LinkedList效率貌似不高

  }
}

//递归:     移动,10层 0, 15层 16, 20层  140, 25层 3547, 30层 112830
//非递归:   移动 10层 16, 15层 16, 20层 110, 25层 3453, 30层 114596,

 

 

分享到:
评论

相关推荐

    递归与迭代算法及其在JAVA语言中的应用.zip

    在编程世界中,递归和迭代是两种基本的解决问题的方法,尤其在Java语言中,它们在...在阅读“递归与迭代算法及其在JAVA语言中的应用.pdf”这份资料后,相信你将对这两者有更深入的理解,并能灵活地应用到实际项目中。

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

    在探讨如何使用Python实现走迷宫问题之前,我们先来了解一下递归算法的基本概念及其应用场景。 **递归**是一种非常重要的算法思想,在计算机科学中有着广泛的应用。简单来说,递归是指一个函数直接或间接地调用自身...

    事业单位考试计算机基础知识:递归算法之解决问题的特点.docx

    对于准备事业单位考试的考生来说,可以参考中公事业单位考试网提供的计算机基础知识知识点梳理,以及其他相关教材和在线资源,来深入学习和理解递归算法及其特点。 总之,递归算法是计算机科学中的一个重要概念,...

    算法与数据结构 算法分析课程 递归算法及归纳法 共56页.pptx

    递归和归纳法之间可以相互替代,在很多情况下,如果能够用归纳法证明某个数学命题,那么同样可以设计出一个递归算法来实现这一命题的计算。 #### 三、递归例程详解 ##### 3.2.1 激活帧与递归过程调用 **激活帧...

    C# 递归算法获取窗体内各控件的属性

    本文将详细介绍如何利用递归算法来获取窗体及其内部所有控件的属性,这在调试、自动化测试或动态配置界面时非常有用。 #### 一、递归算法基础 递归是指函数直接或间接地调用自身的一种编程方法。在本例中,我们将...

    用栈实现二叉树先序遍历的非递归算法实践题.doc

    根据提供的文档信息,可以看出文档似乎包含了不相关的文字内容,并且实际有用的信息主要集中在标题和描述中,即...这种非递归的方法不仅能够提高程序的运行效率,还能够帮助理解栈的工作原理及其在算法设计中的应用。

    数据结构数组稀疏矩阵及广义表、递归实验报告

    本次实验主要分为三个部分:数组稀疏矩阵及广义表的处理、递归算法的设计及其转换。具体目标如下: 1. **掌握各种特殊矩阵的压缩存储方法**: - 对称矩阵、上三角矩阵、下三角矩阵以及对角矩阵等特殊矩阵的存储...

    tr-educ递归.pdf

    ### 递归算法在计算机科学课程中的应用:斐波那契数与二项式系数 #### 一、引言 递归作为一种重要的问题解决及编程技术,在...此外,通过提供简单的证明来展示这些问题,有助于加深学生对递归及其潜在问题的理解。

    递归专题讲座

    总的来说,递归是计算机科学中的重要概念,理解递归及其工作原理对于提升编程能力和解决问题的技巧至关重要。在实际编程中,合理运用递归能够提高代码的可读性和简洁性,但也需要谨慎处理潜在的性能和堆栈深度问题。

    (java递归)删除文件

    在本文中,我们将深入探讨如何使用递归方法在Java中删除文件,这通常涉及到目录及其包含的所有文件和子目录的删除。以下是根据提供的代码片段提炼出的关键知识点: ### 关键知识点一:递归函数设计 递归函数`find...

    漫谈递归思想

    递归思想及其应用 递归思想是编程中的一种重要算法,然而它却是让人摸不着头脑的基本算法之一。许多时候,我们花费很多时间来搞明白一个复杂的递归,尤其是当我们对问题的概念不清晰时。今天,我们来讨论递归思想的...

    算法导论 第三版 Introduction to Algorithms Third Edition

    - **4.3 替代法求解递归式**:解释了如何使用替代法来解决递归关系式。 - **4.4 递归树法求解递归式**:介绍了一种可视化递归过程的方法——递归树法。 - **4.5 主定理求解递归式**:给出了一种快速解决特定类型...

    算法导论第三版 英文原版 超清晰

    - 算法定义及其重要性。 - 算法作为技术的视角。 - **第2章:入门** - 插入排序算法详解。 - 算法分析方法。 - 算法设计原则。 - **第3章:函数的增长** - 渐近符号的介绍与应用。 - 常见函数与标准符号。 ...

    算法导论 第三版 英文 文字版 清晰

    - **4.3 替代法求解递归式**:解释替代法的基本思想及其应用。 - **4.4 递归树法求解递归式**:介绍递归树的概念,并用它来分析递归算法的时间复杂度。 - **4.5 主定理求解递归式**:给出主定理的具体形式,并...

    深度学习批归一化及其相关算法研究进展.docx

    为了解决BN存在的问题,研究人员提出了多种变体和替代算法,如Instance Normalization、Layer Normalization、Group Normalization等。这些方法各有优势,适用于不同的任务和网络结构,但计算复杂度可能会比BN更高,...

Global site tag (gtag.js) - Google Analytics