`

迭代(iteration)和递归(recursion)

阅读更多
Q.请写一段代码来计算给定文本内字符“A”的个数。分别用迭代和递归两种方式。

A.假设给定文本为”AAA rating”。迭代方式就很直观,如下:

public class Iteration {
 
    public int countA(String input) {
        if (input == null || input.length( ) == 0) {
            return 0;
        }
 
        int count = 0;
        for (int i = 0; i < input.length( ); i++) {
            if(input.substring(i, i+1).equals("A")){
                count++;
            }
        }
        return count;
    }
 
    public static void main(String[ ] args) {
          System.out.println(new Iteration( ).countA("AAA rating"));     // Ans.3
    }
}


接下来,递归方式的代码如下:

public class RecursiveCall {
 
    public int countA(String input) {
 
        // 退出条件
        if (input == null || input.length( ) == 0) {
            return 0;
        }
 
        int count = 0;
 
        //检查第一个字符
        if (input.substring(0, 1).equals("A")) {
            count = 1;
        }
 
        //递归调用来计算其结果
        return count + countA(input.substring(1));
    }
 
    public static void main(String[ ] args) {
        System.out.println(new RecursiveCall( ).countA("AAA rating"));  // Ans. 3
    }
}



Q.理解递归需要了解哪些概念?

A. 可重入方法(re-entrant method)是可以安全进入的方法,即使同一个方法正在被执行,深入到同一个线程的调用栈里面也不会影响此次执行的安全性。一个非可重入方法则不是可以安全进入的。例如,加入写文件或者向文件中写入日志的方法不是可重入方法时,有可能会毁坏那个文件。

如果一个方法调用了其自身的话,我们称之为递归调用。假定栈空间足够的话,尽管递归调用比较难以调试,在Java语言中实现递归调用也是完全可行的。递归方法是众多算法中替代循环的一个不错选择。所有的递归方法都是可重入的,但是不是所有可重入的方法都是递归的。

栈遵守LIFO(Last In First Out)规则,因此递归调用方法能够记住“调用者”并且知道此轮执行结束之返回至当初的被调用位置。递归利用系统栈来存储方法调用的返回地址。 Java是一种基于栈设计的编程语言。

顺着这个思路还有那些问题可以用来面试?

Q.什么情况下应该采用递归?

A. 上面的例子中其实不必采用递归,循环的方式可以达到目的,但是在某些情况下采用递归方式则代码会更加简短易读。递归方法在循环树结构以及避免丑陋的嵌套循环的情况下是非常好用的。

Q.什么是尾递归,为什么需要尾递归?上面的代码用尾递归方式如何重写?

A. 常规递归方法(亦称,头递归)在上面演示了,这种方式会增加调用栈的大小。每次递归,其入口需要被记录在栈中。方法返回之前需要给countA(input.substring(1)的结果加一个count。假定count大于1,那么返回结果就是count + countA(input.substring(1)),当然事先要算出来countA(input.substring(1))才行。同时,这也意味着直到countA(input.substring(1)计算出来才能得到最终的结果。因此,最后需要做的事其实是加法运算,而非递归本身。

尾递归的好处是什么?

在尾递归中,最后要做的是递归,加法运算在之前就已经完成了。一轮递归调用完毕后就没有其他事情了(除了加法运算),因此调用时生成的信息也就没什么用了。这些无用信息可以丢弃,然后用一组新的参数来调用一次递归方法来产生一个新的结果。这也就是说,栈调用减少带来了内存消耗减少并且程序的性能更好。

尾递归重写的代码如下:

public class TailRecursiveCall {
 
 public int countA(String input) {
 
  // exit condition – recursive calls must have an exit condition
  if (input == null || input.length() == 0) {
   return 0;
  }
 
  return countA(input, 0) ;
 }
 
 public int countA(String input, int count) {
  if (input.length() == 0) {
   return count;
  }
 
  // check first character of the input
  if (input.substring(0, 1).equals("A")) {
   count = count + 1;
  }
 
  // recursive call is the last call as the count is cumulative
  return countA(input.substring(1), count);
 }
 
 public static void main(String[] args) {
  System.out.println(new TailRecursiveCall().countA("AAA rating"));
 }
}
分享到:
评论

相关推荐

    递归和迭代1

    递归(Recursion)是一种在函数或过程中调用自身的方法。这种方法特别适用于可以分解为相似子问题的问题。通过将大问题分解成小问题,并使用相同的解决方案来解决这些小问题,递归能够以简洁的方式解决复杂问题。 #...

    runtimeAnalysis:幂函数:迭代Vs。 递归的

    本话题将聚焦于幂函数的计算,比较两种常见方法:迭代(Iteration)与递归(Recursion)。我们将深入探讨这两种方法在Java语言中的实现,并分析它们的时间复杂度和实际运行效率。 幂函数是数学中的一种基本运算,...

    计算递归函数调用次数

    为了避免这种情况,可以考虑使用尾递归(Tail Recursion)、记忆化(Memoization)或迭代(Iteration)等优化方法。 尾递归是指在递归调用的最后返回结果,这样编译器或解释器有可能优化掉多余的栈帧,减少内存消耗...

    算法和数据结构——迭代和递推(上).pdf

    首先,“算法和数据结构——迭代和递推(上)”这个标题提示了文档将讨论算法领域中非常核心的两个概念:迭代(Iteration)和递归(Recursion)。这两者在计算机科学中用于实现程序的重复操作和问题求解的基本方法。...

    解决算法分析中递归问题的方法

    本文将详细介绍三种解决递归问题的方法:**替换法(Substitution Method)**、**迭代法(Iteration Method 或 Recursion Tree Method)**以及**主定理(Master Method)**。 #### 1. 替换法(Substitution Method)...

    C语言的逻辑双璧:递归与循环深度解析

    递归与循环是C语言中实现迭代逻辑的两种强大工具,它们各有优势和适用场景。递归提供了一种简洁的方式来解决分而治之的问题,但在使用时需要注意避免栈溢出和重复计算的问题。循环则是一种更为直接且通常更高效的...

    实验一斐波那契数列的实现算法及分析.docx

    非递归(Iteration)算法则通过循环结构替代递归调用,通过迭代的方式计算斐波那契数列。非递归方法初始化两个变量,逐步迭代更新至所需的n项。这种方法的优势在于避免了重复计算,从而大大提高了算法的效率。时间...

    数据结构与算法(2).pdf

    因此,设计递归算法时,应尽量减少递归深度,考虑尾递归优化(tail recursion optimization),或者使用迭代(iteration)作为替代方案。 总的来说,递归是数据结构与算法中不可或缺的一部分,它在解决复杂问题时...

    C语言递归算法程序.rar-综合文档

    此外,优化递归算法,如使用尾递归(tail recursion)或迭代(iteration)替代,可以提高程序性能。 综上所述,“C语言递归算法程序.rar”中的文档很可能涵盖了递归的基础概念、实例、优缺点、实现方法以及如何避免...

    实验报告 程序设计方法学 C++ STLJava泛型程序设计

    - **迭代(Iteration)**:是一种重复执行相同或相似任务的过程,通常通过循环结构实现。迭代适用于不需要分治的情况,或者递归可能带来栈溢出风险的情形。 #### 五、实验内容详解 ##### 实验任务1:递归程序设计 -...

    等式极值问题maxd

    递归与迭代(Recursion and Iteration) 在解决此类问题时,递归和迭代是两种常见的方法。递归通过函数自身调用实现问题的分解和求解,而迭代则通过循环结构逐步解决问题。在这个特定的问题中,快速排序算法使用了...

    数据结构&算法1

    算法方面,分支迭代(branch iteration)、递归(recursion)和搜索(search)是基本操作。二分搜索(binary search)是一种基于分治策略(divide & conquer)的高效算法,通常用于有序数组或二叉查找树中。在解决...

    实用算法的分析与程序设计.pdf

    6. 递归与迭代(Recursion and Iteration):递归算法通过调用自身解决问题,而迭代算法通过重复执行一系列操作直到满足某个条件。理解两者在算法设计中的应用和优化方法是算法分析与程序设计的重要部分。 7. 数据...

    sicp 2016 from

    - **线性递归与迭代 (Linear Recursion and Iteration)**:比较了两种不同的计算方式及其效率差异。 - **树形递归 (Tree Recursion)**:探讨了如何通过递归来解决分治类型的问题。 - **增长阶次 (Orders of ...

    sicp-Structure and Interpretation of Computer Programs

    - **1.2.1 线性递归和迭代**(Linear Recursion and Iteration):比较两种不同的过程结构。 - **1.2.2 树形递归**(Tree Recursion):探讨树形递归的概念及其应用场景。 - **1.2.3 增长阶**(Orders of Growth...

    数据结构与算法分析英文原版第四版 Data Structures and Algorithm Analysis in C++ DSAlgoWeissMark

    - **递归与迭代(Recursion vs. Iteration)**:比较递归调用和循环两种实现方式的优劣。 - **排序算法(Sorting Algorithms)**:介绍了如冒泡排序、选择排序、插入排序、快速排序等多种排序算法及其特性。 - **搜索...

    cisco研发中心面试试题....doc

    - **Recursion vs Iteration**:面试中可能会考察如何使用递归和迭代解决问题。 4. **VoIP技术**: - **H.323**:一种广泛使用的IP电话协议,涉及终端(EP)、网关控制(GK)、计费系统等组件。 - **SIP...

    Leetcode:解决来自leetcode的问题

    此外,LeetCode中的问题往往涉及特定的编程技巧,如递归(Recursion)、迭代(Iteration)、双指针(Two Pointers)、位运算(Bit Manipulation)等。递归是函数自身调用,常用于树结构和回溯算法;迭代是通过循环来解决问题...

    Data-Structures-in-Python

    14. **迭代(Iteration)**: Python中的for循环和while循环是迭代的基础,可用于遍历任何可迭代对象,如列表、元组、字符串等。 15. **Jupyter Notebook**:这是一个交互式环境,结合了代码、文本、公式和图像,非常...

Global site tag (gtag.js) - Google Analytics