仅用递归和栈操作逆序一个栈

本文详细解析了一种利用递归实现栈中元素逆序的算法。通过对递归过程的逐步推导,阐述了如何通过递归函数前后的操作顺序及递归栈特性,实现栈内元素从正序到逆序的转变。

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]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值