1 根据结果推测代码
| 3 | | 1 |
----- -----
(A) | 2 | => (B) | 2 |
----- -----
| 1 | | 3 |
----- -----
根据【递归栈】返回的时候是逆序的这一特性,我们知道递归函数之前的操作是顺序的,递归之后的操作是逆序的,不难推测出三点:
(1)递归返回的时候stack一定是空的,这就是收敛条件;
(2)得到B这样的结果,递归栈必然是 push v=3,push v=2, push v=1造成的;
(3)所以,递归函数之前得到局部变量v的操作,必然是顺序得到 1,2,3的。
综上所述,可以推测代码的形式是:
public static void reverse(Stack<Integer> stack) {
// 收敛条件
if (stack.isEmpty()) {
return;
}
// 递归函数之前的操作,顺序执行
int v = getAndRemoveLast(stack); // v 的结果顺序是 1,2,3
// 递归函数
reverse(stack);
// 递归函数之后的操作,逆序执行
stack.push(v); // 3, 2, 1
}
编写getAndRemoveLast
根据int v = getAndRemoveLast(stack); // v 的结果顺序是 1,2,3并且最后栈为空,我们给出了getAndRemoveLast这个名字,也代表了它的作用。所以我再来一次通过结果推测代码:
| 3 |
-----
(A) | 2 | => (B) | 3 |
----- -----
| 1 | | 2 |
----- -----
结果push的顺序是 2,3;(逆序)
pop的顺序是3,2,1;(顺序)
所以递归函数前后的操作基本上确定了。
递归出口,也就是收敛条件也往往比较单调,就是empty,只不过,这里当stack.isEmpty()的时候,返回的是最后一个元素,所以代码推测如下:
private static int getAndRemoveLast(Stack<Integer> stack) {
int result = stack.pop();
if (stack.isEmpty()) { // 说明刚刚pop的是最后一个元素
return result;
} else { // 说明不是最后一个元素
/*
* 如果last获得了返回,说明真的递归到了收敛条件,也就是到达最后一个元素了。
* 期间,递归的每一层的局部变量result都保存在【递归栈】中。
* 递归函数之前的操作(pop)是顺序的,递归之后的操作(push)是逆序的,
* pop:5,4,3,2,1;push:2,3,4,5
* */
int last = getAndRemoveLastElement(stack);
stack.push(result);
return last;
}
}
验证:
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
for (int i = 1; i <= 5; i++) {
stack.push(i);
}
int last = getAndRemoveLastElement(stack);
System.out.println("last:" + last);
printStack(stack);
}
输出:
last:1
[2, 3, 4, 5]
完整代码
import java.util.Arrays;
import java.util.Stack;
public class StackAndQueue {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
for (int i = 1; i <= 5; i++) {
stack.push(i);
}
printStack(stack);
reverse(stack);
printStack(stack);
}
public static void reverse(Stack<Integer> stack) {
// 收敛条件
if (stack.isEmpty()) {
return;
}
// 递归函数之前的操作,顺序执行
int v = getAndRemoveLast(stack); // v 的结果顺序是 1,2,3
// 递归函数
reverse(stack);
// 递归函数之后的操作,逆序执行
stack.push(v); // 3, 2, 1
}
private static int getAndRemoveLast(Stack<Integer> stack) {
int result = stack.pop();
if (stack.isEmpty()) { // 说明刚刚pop的是最后一个元素
return result;
} else { // 说明不是最后一个元素
/*
* 如果last获得了返回,说明真的递归到了收敛条件,也就是到达最后一个元素了。
* 期间,递归的每一层的局部变量result都保存在【递归栈】中。
* 递归函数之前的操作(pop)是顺序的,递归之后的操作(push)是逆序的,
* pop:5,4,3,2,1;push:2,3,4,5
* */
int last = getAndRemoveLast(stack);
stack.push(result);
return last;
}
}
private static void printStack(Stack<Integer> stack) {
System.out.println(Arrays.toString(stack.toArray()));
}
}
输出:
[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]
本文详细解析了一种利用递归实现栈中元素逆序的算法。通过对递归过程的逐步推导,阐述了如何通过递归函数前后的操作顺序及递归栈特性,实现栈内元素从正序到逆序的转变。

被折叠的 条评论
为什么被折叠?



