【死磕算法·栈和队列】仅用递归实现栈的逆序

题目要求:实现栈的逆序,但只能用递归函数和这个栈本身操作来实现,不能自己申请额外的数据结构。

题目思路:

实现两个递归函数:

getBottomItem():移除栈底元素并返回该元素

reverse():实现整个栈逆序

如何写递归函数?

递归函数在函数体中调用自己,对不同的值进行重复操作。

递归函数三要素:

1、要有可以退出函数的情况;

2、递归过程中将一个问题简化到更小的规模,递归函数的参数规模一定是越来越小的

3、父问题和子问题不能有重叠。

但更重要的是,得知道递归半天,写这个函数最后要返回什么或者达成什么效果,进而思考要怎样一步步去达到目的。

getBottomItem():

这个函数的目的是要得到栈底元素并移除,分三步走:

1、把栈底元素上面的元素一个个的都弹出来;

2、得到并移除栈底元素;

3、将之前在栈底元素上面的元素再压回栈中去。

递归总要有个结尾,如果把递归函数比作”俄罗斯套娃“,我们得不断把外壳拿掉直到得到最小的”实心娃娃“,这个递归函数的结尾在于得到并移除栈底元素。那么我们由函数体前几行就已经确定了:
 

public int getBottomItem(stack<int> s){

    int nowItem = s.pop();

    if(s.isEmpty()){ //递归到底要执行的操作

        return nowItem;

    }
    
    else{

        ...

    }

}

接下来我们填else 括号体的内容:

首先,函数不继续递归无法触底,把新栈作为参数继续调用递归函数,递归函数触底返回到这一层时会把栈底元素也返回,因此int last = getBottomItem(s)来存储返回的栈底元素值。

看递归到底已经获得栈底元素之后,我们应该做什么——把原来在栈底元素上面的元素按原来顺序压入栈中

我们已经获得了这一层里移除的非栈底元素nowItem,接下来要把这一层的nowItem压入栈中 s.push(nowItem)

返回到递归函数的最顶层,递归函数把原来的栈顶元素重新压入到栈中,

不要忘了我们还在递归函数内,而最后的目标是返回栈底元素,因此函数最后返回栈底元素last。

最后getBottomItem()实现如下:


    public int getBottomItem(stack<int> s){
        int nowItem = s.pop();
        if(s.isEmpty())//递归到底
            return nowItem;
        else{//
            int last = getBottomItem(s)//没递归到底的时候,我们要用一个变量存储返回的栈底元素;
            s.push(nowItem)//把这一层的栈元素压入栈中
            return last;
        }
         
}

我们再来看reverse()函数。

reverse函数的目的是让栈逆序,栈顶元素要在栈底。同样的我们首先将这个问题拆解成步骤:

1、调用getBottomItem获取栈底元素并移除,直到我们得到栈顶元素并移除,此时栈为空,递归到底

2、把栈顶元素压入栈底,其他元素按照最后后移除的先入栈的原则入栈,实现栈的逆序。

public void reverse(stack <int> s){
  if(s.isEmpty())
        return;
  int bottom = getBottomItem(s);
  reverse(s);
  s.push(bottom);
}

在向下一层层递归中栈底元素被移除,直到栈中只有栈顶元素,栈顶元素被移除后继续递归,栈为空,此时递归函数开始向上返回。

返回上一层后,bottom值即为原栈顶值,注意到此时栈为空,要把他压入栈底,即s.push(bottom)

总结

写递归函数只要考虑到:

1、递归函数向下递归终结的条件是什么,要返回什么,把这段代码写在函数题的前面。

2、向下递归结束开始向上返回时,假设只到了触底反弹的上一层, 考虑我们在递归结果的基础上如何操作,写在“自己调用自己”的下面。

以下是一个递归函数体内部的必要步骤和前后逻辑:

Public int  recursiveFunction(s):

1、获取递归函数触底时需要返回的值(可选)

2、通常以if语句开头,向下递归的终结条件及返回(如果递归函数需要返回某值,在这之前要获取该值)

3、通常以else语句开头,在调用自己之前保证对参数s进行过处理,使其规模简化。

4、recursiveFunctions

5、向下递归到底,向上返回时到上一层,考虑要在向下递归到底的基础上进行什么操作。

6、返回递归函数从最底端开始往上传递的值(可选)

栈逆序代码实现:

class StackReverse {
public:
        int getBottomItem(vector <int> &s){
        int nowItem = s.back();//返回最后向量尾部最后一个元素
            s.pop_back();//从向量尾部弹出一个元素
        if(s.empty())//递归到底
            return nowItem;
        else{//
            int last = getBottomItem(s);//没递归到底的时候,我们要用一个变量存储返回的栈底元素;
            s.push_back(nowItem);//把这一层的栈元素压入栈中,用vector的push_back()函数实现,向向量尾部增加一个元素
            return last;
        }
         
    }
    void reverse(vector <int> &s){
        if(s.empty())
            return;
        else{
            int bottom = getBottomItem(s);
            reverse(s);
            s.push_back(bottom);//自下向上把后弹出的值先压入栈中,实现逆序
        }
    }
    vector<int> reverseStack(vector<int> A, int n) {
        // write code here
        reverse(A);
        return A;
    }
};

猜你喜欢

转载自blog.csdn.net/gulaixiangjuejue/article/details/85038254