题目要求:实现栈的逆序,但只能用递归函数和这个栈本身操作来实现,不能自己申请额外的数据结构。
题目思路:
实现两个递归函数:
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、recursiveFunction(s) |
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;
}
};