递归反转栈的顺序-------只使用常数量个变量

昨天去阿里巴巴参加Java研发工程师的实习生面试,遇到的一个题目:

我们要反转一个栈,如果使用另外一个栈作为辅助的话,那么反转起来很简单,一个接一个push到辅助栈里再push回来就行了。那么假如不能使用辅助栈,数组等空间为O(n)的数据结构,只使用O(1)的空间复杂度即只能有常数个变量,怎么实现将栈反转?即原来的栈顶在栈底,栈底变成栈顶。

 

面试官提示我使用递归来考虑。当时我没有想出来……

这道题使得我对递归算法的理解,感觉提升了一小下。

让我懂得了递归算法不能考虑中间过程,上一层的递归可以直接使用下一层的递归结果,即假设下一层已经完成了我们的要求就行了,最后只需要考虑最后一层递归退出的条件就行了。

回来以后想,这道题大概是这样的:

先画图:

  • 首先假设栈里面从栈底到栈顶存储的依次是 1 2 3 4 5,我们反转以后希望得到的结果是 5 4 3 2 1.
  • 第一步pop出来第一个数5,存到temp1中,此时的栈中由下到上是1 2 3 4。
  • 递归调用自身,不用考虑具体的过程,我们只需要知道这个递归调用结束后得到的结果是使栈中的元素变成了由下到上 4 3 2 1(因为这个函数本身的意思就是反转栈)。
  • 此时pop出来第二个数1 ,存到temp2中,此时的栈中由下到上是 4 3 2。
  • 再递归调用本身,抽象考虑这个递归完成后得到的结果是栈中的值变成了 2 3 4。
  • 接着我们把push(temp1),栈变成了 2 3 4 5。
  • 接着递归调用本身,递归完成后栈变成了 5 4 3 2。
  • 接着push(temp2)。好了,栈变成了 5 4 3 2 1,反转完成!

接下来我们需要考虑递归函数结束的条件了,该函数的结束条件是当栈为空或者栈里只有一个元素的时候,return。

如何知道栈里只有一个元素?

我们可以先记录下栈顶元素,然后pop,如果栈变成空,则说明是只有一个元素,push回去再return。

 

结合上图和思路,给出代码:

#include <iostream>
#include <stack>
using namespace std;

void printInfo(stack<int> s){
    int a ;
    while(!s.empty()){
        a = s.top();
        cout << a << " . " ;
        s.pop();
    }
    cout << endl;
    return ;
}

void reverseStack(stack<int> &s){
    if(s.empty())
        return ;
    else {
        //如果s里面只有一个元素,就返回,否则就不返回。具体实现是先pop出来一个,判断剩下的是不是空栈。
        int a = s.top();
        s.pop();
        if(s.empty()){
            s.push(a);
            return ;
        }
        else{
            s.push(a);
        }
    }
    int temp1 = s.top();
    s.pop();
    reverseStack(s);
    int temp2 = s.top();
    s.pop();
    reverseStack(s);
    s.push(temp1);
    reverseStack(s);
    s.push(temp2);
}

int main(){
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    s.push(5);
    cout << "-------------before recursion------------" << endl;
    printInfo(s);
    
    cout << "-------------after  recursion------------" << endl;
    reverseStack(s);
    printInfo(s);

    system("pause");
    return 0;
}

 

运行结果:

posted on 2014-04-15 13:34  Allen Blue  阅读(3825)  评论(7编辑  收藏  举报

导航