翻转栈中的元素(不使用额外数组或者队列)

如果想要反转栈中的元素,可以使用队列作为辅助数据结构的话,就来回倒腾一下就可以了。

但是如果不使用队列应该怎么做呢?今天百度面试就被问到了。。。

那必然就是使用递归来操作了,关键是怎么去组织递归呢?

下来考虑简单的问题,如何将栈底的元素挪动到栈顶?也就是这样:
在这里插入图片描述

怎么把0挪动到最上面?

我们需要获取0,可是使用一个自下而上的递归把最底下的0传递出来(作为递归返回值):

int get(stack<int> &s){
    int v = s.top();
    s.pop();
    if(s.empty())   return v;//v就是栈底的元素,不用压回栈,将它一层层往上传递
    else{
        int last = get(s);//获取值
        s.push(v);//恢复栈,也就是把pop出来的值压回去
        return last;//把值往上传递
    }
}

上述代码就可以得到栈底的元素,然后将栈底元素push就可以达到图示的效果了。

ok,现在回顾最开始的问题,反转栈中的所有元素,那就需要我们递归地对栈进行把栈底元素移动到栈顶这个过程

所以总的代码就是:

int get(stack<int> &s){
    int v = s.top();
    s.pop();
    if(s.empty())   return v;//v就是栈底的元素,不用压回栈
    else{
        int last = get(s);//获取值
        s.push(v);//恢复栈,也就是把pop出来的值压回去
        return last;//把值往上传递
    }
}

void reverse(stack<int> &s){
    if(s.empty())   return;
    int val = get(s);//保存栈底元素(同时栈中元素数量-1)
    reverse(s);
    s.push(val);//栈底元素push到栈顶
}

说实话这个思路还是比较难想到的。仔细分析的话,可以发现reverse函数实际上是使用了一个函数栈来存储每次递归的栈的元素,那么可以换个思路,如果使用两个栈怎么进行翻转元素呢?也就是可以使用另一个栈作为辅助数据结构。

有两个相同的栈,一个里面放着自大到小排列的数,栈顶的数最小,另一个栈是空的。不允许利用其它的数据结构,只能利用这两个栈,要求把第一个栈里的数字反过来,从小到大排列,结果还放在原来的那个栈里面。

思路和上面是类似的,只不过不是使用函数栈,而是真的使用一个栈:
利用两个栈,反转其中一个栈的元素 - hust_枫 - 博客园

思路:假设stackA存放数,stackB为辅助栈。stackA元素个数为N。

第1次操作:先取stackA栈顶元素,记为tmp,然后把剩余N-1个元素转移到stackB中,接着把tmp和stackB的N-1个元素依次压入stackA中,这样完成了stackA原栈顶的反转。

第2次操作:先取stackA栈顶元素,记为tmp,因为栈底有一个元素已完成反转,故只需要把剩余的N-2个元素转移到stackB,接着把tmp和stackB的N-2个元素依次压入stackA中,这样完成了stackA原栈顶第二个元素的反转。

第i次操作:先取stackA栈顶元素,记为tmp,之前已有i-1个元素完成反转,只需要把栈顶的N-i+1个元素转移到stackB,接着把tmp和stackB的N-i+1依次压入stackA中。

注意:第N次操作时,因为前面N-1次操作已完成,而此时的栈顶就是初始的栈底,故第N次操作不需要做。总的过程只需要N-1次操作。

void ReverseStack(stack<int> &a){
    stack<int> b;
    int n = a.size();
    for(int i = 0; i < n-1; ++i){
        int val = a.top();
        a.pop();
        while(a.size() > i){
            b.push(a.top());
            a.pop();
        }
        a.push(val);//首元素到了栈底
        while(!b.empty()){
            a.push(b.top());
            b.pop();
        }
    }
}

总的来说,思路都是有一点难度的,画画图辅助理解会好很多。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值