题目

面试题 03.05. 栈排序 - 力扣(LeetCode)

栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:pushpoppeek 和 isEmpty。当栈为空时,peek 返回 -1。

示例1:

输入

["SortedStack", "push", "push", "peek", "pop", "peek"]
[[], [1], [2], [], [], []]

输出

[null,null,null,1,null,2]

示例2:

输入

["SortedStack", "pop", "pop", "push", "pop", "isEmpty"]
[[], [], [], [1], [], []]  

输出

[null,null,null,null,null,true]

说明:

  1. 栈中的元素数目在[0, 5000]范围内。

分析

栈是先进后出,对栈进行排序,将这个栈命名为数据栈A,使最小元素位于数据栈的栈顶,也就意味着栈底是最大的元素,先放进去的是最大的元素,然后按顺序递减到最小元素。

题目说可以使用一个辅助栈来实现,命名为辅助栈B,那么辅助栈内的元素存储数据的时候,数据大小顺序应该是反过来,也就是最大元素位于辅助栈B的栈顶。 这样从辅助栈B迁移数据到数据栈A的时候,刚好满足题目需求。

排序的时候,使用前后堆叠的方式进行即可,比如说,以一组排好顺序的数据作为一组,如果比这组数据最大的大,就放在大的一端,比这组数据的最小的数据小,就放在小的一端。

比如类似数据如下:

data_stackA: 8 9 2 3 1 7 5 
sort_stackB: 
  1. 为了使数据栈A最小元素位于栈顶,则必须让数据A中小的元素放在辅助栈B的栈底。 从数据栈A取出 5 放入辅助栈B
data_stackA: 8 9 2 3 1 7
sort_stackB: 5 
  1. 继续比较 数据栈A的数据 7 比 辅助栈B的栈顶5还大,将大的数据 7 放入 辅助栈B。
data_stackA: 8 9 2 3 1
sort_stackB: 5 7
  1. 继续比较 数据栈A,发现 1 比辅助栈B栈顶7小,则说明当前不是合适的存放位置,将 1 存放入临时变量data_tmp中,然后将数据栈A的1释放掉
data_stackA: 8 9 2 3
data_tmp: 1
sort_stackB: 5 7
  1. 再将辅助栈B数据重新依次和临时变量data_tmp进行比较,如果辅助栈B栈顶数据大于临时变量data_tmp,就重新压回数据栈A中,如果小于,则将临时变量data_tmp压入辅助栈B,然后清空辅助变量data_tmp。
data_stackA: 8 9 2 3 7 5
data_tmp: 
sort_stackB: 1
  1. 然后可以将5 7 重新压回辅助栈B, 这时候相当于辅助栈B的 5 7 数据作为了一组有序数据进行了移动,后续循环进行2~4进行数据分组堆叠操作操作即可完成辅助栈排序。
data_stackA: 8 9 2 3
data_tmp: 
sort_stackB: 1 5 7
  1. 完成辅助栈B的排序后,将辅助栈数据B重新压入数据栈A即可得到结果
data_stackA: 
data_tmp: 
sort_stackB: 1 2 3 5 7 8 9 

只用一个栈的代码规则汇总

  1. 构建临时变量data_tmp和辅助栈B
  2. 如果临时变量data_tmp没有数据,则遍历数据栈A,如果数据栈A栈顶比辅助栈B顶大,则将数据栈A数据压入辅助栈B,同时释放数据栈A这个数据,否则放入临时变量data_tmp,同时释放数据栈A的这个数据。
  3. 如果临时变量data_tmp有数据,则比较临时变量data_tmp是否大于辅助栈B栈顶,如果大于,则将临时变量data_tmp放入辅助栈B栈顶,否则将辅助栈B栈顶数据压入数据栈A中。
  4. 重复操作2和3,直到数据栈A数据清零,且临时变量data_tmp中没有数据,然后重新将辅助栈B数据压入数据栈A,得到的即为要求结果。

使用共两个栈保存数据

如果能使用两个栈进行数据保存的话,那么只需要维护两个栈,一个栈总是顺序排序,另一个栈总是逆序排序,
在插入数据的时候动态调整插入数据位置,就能减少在push操作中重复传递数据的次数,进而能提高性能。

通过例子来说明, 现有数据data 8 9 2 3 1 7 5

data: 8 9 2 3 1 7 5 
data_stackA: 
data_tmp: 
  1. 始终保证 数据栈 data_stackA 的数据比 辅助栈 data_tmp 的大,并将data_stackA作为最小栈,data_tmp 作为最大栈。先添加 5 入数据栈 data_stackA
data: 8 9 2 3 1 7
data_stackA: 5
data_tmp: 
  1. 继续添加 7 , 因为 7 比 data_stackA 栈顶数据5大,又因为 data_stackA 数据需要大于 data_tmp ,因此要将 data_stackA 数据压入data_tmp,然后再继续把 7 压入 data_stackA。
data: 8 9 2 3 1
data_stackA: 7
data_tmp: 5
  1. 继续重复 1~2 操作,直到存入所有数据
  2. 在peek取出数据或pop操作的时候,要将临时最大栈data_tmp 数据压入数据最小栈data_stackA,因为data_stackA数据始终比data_tmp大,因此最后data_stackA 数据为最小栈。

两个栈编码规则

  1. push操作中,如果插入数据data始终比最小栈data_stackA大,则将data_stackA数据压入data_tmp,然后将data压入data_stackA。
  2. push操作中,如果插入数据data比最小栈data_stackA小,但是比最大栈data_tmp大,则直接将data压入data_stackA。
  3. push操作中,如果插入数据data始终比最大栈data_tmp小,则将data_tmp数据压入data_stackA,然后将data压入data_stackA。
  4. seek或pop操作中,如果最大栈data_tmp中存在数据,则将data_tmp数据压入data_stackA。
  5. 将数据最小栈data_stackA 定义为 m_min_stack , 将辅助最大栈data_tmp定义为 m_max_stack

代码

只用一个栈排序的代码

 
#include <stack>
 
class SortedStack {
public:
    SortedStack()
    {
    }
 
    void push(int val)
    {
        if (val < 0)
            return;
 
        m_data.push(val);
 
        this->sort();
    }
 
    void pop()
    {
        if (m_data.empty())
            return;
        
        m_data.pop();
    }
 
    int peek()
    {
        if (m_data.empty())
            return -1;
 
        return m_data.top();
    }
 
    bool isEmpty()
    {
        return m_data.empty();
    }
 
private:
    void sort()
    {
        // sort 
        int tmp_data = -1;
        std::stack<int> stackB;
 
        while (!m_data.empty() || tmp_data >= 0) {
 
            if (tmp_data >= 0) {
                while (!stackB.empty() && tmp_data <= stackB.top()) {
                    m_data.push(stackB.top());
                    stackB.pop();
                }
                stackB.push(tmp_data);
                tmp_data = -1;
                continue;
            }
 
            if (stackB.empty() || m_data.top() >= stackB.top()) {
                stackB.push(m_data.top());
            } else {
                tmp_data = m_data.top();
            }
            m_data.pop();
        }
 
        while (!stackB.empty()) {
            m_data.push(stackB.top());
            stackB.pop();
        }
    }
 
    std::stack<int> m_data;
};
 

数据栈+辅助栈排序代码

#include <stack>
 
class SortedStack {
public:
    SortedStack()
    {
    }
 
    void push(int val)
    {
        if (m_min_stack.empty()) {
            m_min_stack.push(val);
            return;
        }
        if (val >= m_min_stack.top()) {
            while (!m_min_stack.empty() && val >= m_min_stack.top()) {
                m_max_stack.push(m_min_stack.top());
                m_min_stack.pop();
            }
            m_min_stack.push(val);
            return;
        }
        // val < min_stack.top
        if (m_max_stack.empty()) {
            m_min_stack.push(val);
            return;
        }
 
        // val < min_stack.top
        if (val >= m_max_stack.top()) {
            m_min_stack.push(val);
            return;
        }
 
        // val < max_stack.top < min_stack.top 
        while (!m_max_stack.empty() && val <= m_max_stack.top()) {
            m_min_stack.push(m_max_stack.top());
            m_max_stack.pop();
        }
        m_min_stack.push(val);
    }
 
    void pop()
    {
        if (this->isEmpty())
            return;
 
        while (!m_max_stack.empty()) {
            m_min_stack.push(m_max_stack.top());
            m_max_stack.pop();
        }
        
        m_min_stack.pop();
    }
 
    int peek()
    {
        if (this->isEmpty())
            return -1;
 
        while (!m_max_stack.empty()) {
            m_min_stack.push(m_max_stack.top());
            m_max_stack.pop();
        }
 
        return m_min_stack.top();
    }
 
    bool isEmpty()
    {
        return m_min_stack.empty() && m_max_stack.empty();
    }
 
private:
    std::stack<int> m_min_stack;
    std::stack<int> m_max_stack;
};
 
#ifdef __TEST__
#include <iostream>
 
int main(int argc, char* argv[])
{
    SortedStack* p_s = new SortedStack;
 
    p_s->push(8);
    p_s->push(9);
    p_s->push(2);
    p_s->push(3);
    p_s->push(1);
    p_s->push(7);
    p_s->push(5);
 
    int t = p_s->peek();
    std::cout << "top: 1 == " << t << "\n";
    p_s->pop();
 
    t = p_s->peek();
    std::cout << "top: 2 == " << t << "\n";
    p_s->pop();
 
    t = p_s->peek();
    std::cout << "top: 3 == " << t << "\n";
    p_s->pop();
 
    t = p_s->peek();
    std::cout << "top: 5 == " << t << "\n";
    p_s->pop();
 
    t = p_s->peek();
    std::cout << "top: 7 == " << t << "\n";
    p_s->pop();
 
    t = p_s->peek();
    std::cout << "top: 8 == " << t << "\n";
    p_s->pop();
 
    t = p_s->peek();
    std::cout << "top: 9 == " << t << "\n";
    p_s->pop();
 
    delete p_s;
 
    return 0;
}
 
#endif //__TEST__
 

*****