基础很重要,这是永远不变的真理。
package sunfa;
public class DiGui {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>(5);
for (int i = 0; i < 5; i++) {
stack.push(i);
}
System.out.println("dg:");
dg(stack);
System.out.println("jc:");
System.out.println(jc(10));
System.gc();
System.out.println("wjc:");
int r = 1;
System.out.println(wjc(10, r));
}
/*
* 要求:栈内的元素要求从栈底开始打印。
*
* 递归编程涉及到栈,也就是说比如一个函数在执行的时候遇到了一个递归函数,那么它执行完了该递归函数后必须会执行递归函数后门的代码,
* 反过来说就是这个递归函数后面的代码必须在该递归函数执行完了后才能得到执行。
*
* 原理:一个函数执行过程中遇到递归(可能是自己或别人的),那么它后面的代码会进行入栈处理,如果这句入栈的代码是这个函数的
* 最后一句代码,那它肯定就只能最后被执行了。
*
* 用途:比如并查集的路径压缩、平衡二叉树的系列的路径修复(下面的元素通过旋转往上升)都是基于递归的这个特点的。
*/
private static void dg(Stack<Integer> stack) {
if (stack.count() > 0) {
Object o = stack.poll();
dg(stack);
System.out.println(o);
}
}
private static void fdg(Stack<Integer> stack) {
while (stack.count() > 0) {
Object o = stack.poll();
dg(stack);
System.out.println(o);
}
}
/*
* 普通递归:
* jc(5)==>
* 5*jc(4)--->表达式入栈
* 5*4*jc(3)--->上一步的jc(4)是递归表达式,所以此处要先对其进行出栈,计算完jc(4)=4*jc(3)后在将表达式4*jc(3)入栈
* 5*4*3*jc(2)--->同上
* 5*4*3*2*jc(1)--->同上
* 5*4*3*2*jc(1) ==>由于n=1的时候函数返回的是一个常数1,这个时候表达式变成5*4*3*2*1,不含有任何函数了,
* 所以开始计算该表达式的结果,计算结果的过程也是一个出栈并计算的过程。
*/
private static int jc(int n) {
if (n == 1)
return 1;
return n * jc(n - 1);
}
/*
* 尾递归:
* wjc(5,1)==>
* wjc(4,5)
* wjc(3,20)
* wjc(2,60)
* wjc(1,120)
* 尾递归是把每一步的结果都计算好了,所以不存在表达式入栈的缺点。
*
* 很明显,普通递归并没有计算每一步的结果,而是到最后一步才去计算的, 它的每一步都包含一个表达式,这个表达式
* 用栈来存放,当然栈顶的肯定是一个表达式,所以每一步生成的表达式入栈后到下一步的时候把栈顶的表达式出栈,并解该
* 表达式,一直如此直到栈内不存在函数,这个时候才开始计算,如果没有退出条件或因为栈已满了那就会栈溢出。
*
*/
private static int wjc(int n, int r) {
return n == 1 ? r : wjc(n - 1, r * n);
}
}
分享到:
相关推荐
7. **实验二**:根据标签,这可能是课程或教材中的第二个实验,旨在加深学生对编译原理中递归下降分析的理解和应用能力。 通过这个资源,学习者可以学习到如何设计和实现一个简单的编译器前端,理解如何处理源代码...
### 关于尾递归 尾递归是一种特殊的递归形式,在这种形式中,递归调用是函数中的最后一个操作。也就是说,递归调用之后没有其他待执行的操作。这种递归形式的重要之处在于它可以被优化为迭代过程,从而避免了传统...
1. **尾递归**:如果递归调用是函数的最后一个操作,并且返回值直接传递给调用者,那么这个递归被称为尾递归。尾递归可以通过编译器或解释器优化,避免额外的栈空间开销。 2. **记忆化**:对于重复计算的问题,可以...
Python递归是编程中一种强大的技术,它允许函数在解决问题时自我调用。递归的基本原理是通过将复杂问题分解为相同或相似的子问题来解决。...在实际编程中,理解递归和尾递归的概念对于编写高效和优雅的代码至关重要。
在尾递归中,先执行某部分的计算,然后开始调用递归,所以你可以得到当前的计算结果,而这个结果也将作为参数传入下一次递归。这也就是说函数调用出现在调用者函数的尾部,因为是尾部,所以其有一个优越于传统递归之...
6. **尾递归优化**:某些Java编译器支持尾递归优化,这允许在不增加额外堆栈空间的情况下进行递归调用。不过,Java标准版目前并不默认开启这一优化,但在Java 14及以上版本的JDK中,可以使用`@jdk.internal.vm....
因此,通常需要对文法进行转换,消除这些递归形式,如采用尾递归优化或者预处理。 在提供的`01.cpp`文件中,很可能包含了一个使用递归下降解析技术的简单编译器或解释器的实现。通常,这样的实现会包括一系列的函数...
1. **尾递归**:如果递归调用是函数的最后一个操作且没有其他操作依赖于递归调用的结果,那么可以优化为尾递归,一些编译器和解释器会优化尾递归,避免栈溢出。 2. **记忆化**:对已经计算过的子问题结果进行缓存,...
1. **尾递归优化**:通过修改函数调用顺序,避免无限递归。 2. **辅助函数**:对于不能直接映射到递归函数的文法规则,可以使用辅助函数来辅助解析。 3. **LR(Look-Ahead)分析**:添加向前看的字符,帮助解决右...
同时,可以考虑对解析器进行性能优化,例如使用尾递归、缓存中间结果等技术。 在提供的文件“Csecond”中,可能包含了实验的代码实现或者实验指南,这些资源可以帮助进一步理解递归下降分析的实现细节和具体应用。...
- **尾递归优化**:一些编译器或解释器可以识别尾递归并将其优化为迭代,避免栈溢出。 - **记忆化**:对于重复计算的问题,可以使用缓存存储已计算过的子问题结果,避免重复计算。 7. **递归与迭代**: 很多递归...
**尾递归优化**:如果递归函数的最后一个操作是递归调用本身,则称为尾递归。C++编译器通常能自动对尾递归进行优化,减少栈空间的使用。 **非递归方法**:也可以使用循环结构(如for循环)来计算阶乘,这种方式不会...
尾递归是指递归调用是函数体的最后一个操作,且没有其他操作依赖于这个递归调用的结果。这样的递归调用可以通过编译器或解释器优化,使其不增加额外的栈空间。在某些语言中,尾递归被默认优化,使得递归函数可以...
总结,递归函数在VB6.0中可以通过基础递归和尾递归两种方式实现,虽然尾递归优化在VB6.0中不可行,但了解其原理有助于理解递归的优化方法。通过深入学习递归函数,开发者能够更好地解决复杂的问题,并提高代码的效率...
为了避免这种情况,可以考虑使用尾递归(Tail Recursion)、记忆化(Memoization)或迭代(Iteration)等优化方法。 尾递归是指在递归调用的最后返回结果,这样编译器或解释器有可能优化掉多余的栈帧,减少内存消耗...
在实际应用中,我们可以通过一些技巧来改进递归下降解析器,例如使用LR分析、LL(*)分析等技术,以处理更复杂的情况,同时可以使用尾递归优化和预测分析等策略提高效率。 在实现递归下降语法分析器时,我们需要仔细...
在某些支持尾递归优化的语言中(如Scheme),这样的递归不会增加额外的堆栈空间。Python 3.7以后的版本对尾递归进行了优化,但并不完全支持,因此仍需谨慎使用。 6. **常见递归问题** - **斐波那契序列**:递归...
对于右递归,如`<factor> ::= <factor> * <atom>`,可以通过尾递归优化避免无限递归。 递归下降法的优点是实现简单,易于理解和调试。缺点是不适用于所有文法,特别是那些包含左递归或需要回溯的文法。对于这些情况...
递归原理递归是一种解决问题的方法,通过使用调用自身的函数作为子程序。您可能会想知道我们如何实现一个调用自身的函数。诀窍在于每次递归函数调用自身时,它都将给定问题简化为子问题。递归调用继续进行,直到达到...
为了解决这些问题,有时可以采用尾递归优化、动态规划或循环替代递归等策略。 在学习递归算法的过程中,有几点是需要注意的。首先,理解递归算法的原理是基础,包括它的定义、它如何将大问题分解为小问题。其次,...