排序堆栈的算法

Posted

技术标签:

【中文标题】排序堆栈的算法【英文标题】:Algorithm for sorting a stack 【发布时间】:2021-11-02 17:24:05 【问题描述】:

给定一个栈,任务是对它进行排序,使得栈顶的元素最大。

示例 1:

输入: 堆栈:3 2 1 输出:3 2 1 示例 2:

输入: 堆栈:11 2 32 3 41 输出:41 32 11 3 2

你的任务:

预期时间复杂度:O(N*N) 预期辅助空间:O(N) 递归。

约束: 1

【问题讨论】:

栈是如何实现的?是否使用了特定的语言? 如果这是家庭作业,你应该使用课程中介绍的方法;你的教授可能会对不同的解决方案感到满意,即使它在客观上更好,如果它不能证明对课程材料的理解 【参考方案1】:

您似乎被禁止在训练中使用除堆栈之外的任何数据结构。

您可以使用第二个堆栈对堆栈进行排序。

例如 - 在每个阶段选择最小元素。

弹出顶部元素并将其放入smin变量中。

弹出所有其他元素。如果当前一个小于smin,则将smin推入第二个堆栈并放入新值。

毕竟,将smin 推入空的主堆栈,然后将第二个堆栈中的所有元素移入主堆栈。

重复但进行n-1 步骤(如果您的堆栈没有Count 属性,您可以在移动元素时记住计数)。重复直到所有元素都排序完毕(未排序的剩余大小变为1)

【讨论】:

【参考方案2】:

堆栈已预先填充 您可以尝试将堆栈的每个元素弹出到一个数组中(O(n)辅助空间)。根据你最喜欢的排序算法对数组进行排序(有算法可以在 O(nLog(n)))

堆栈为空 改用优先队列:|

【讨论】:

【参考方案3】:

如果您能够将最小的元素移动到堆栈的底部,那么您就完成了(因为您可以反复执行此操作,每次都缩小堆栈)。

要将最小的元素移到底部,请将所有元素移至辅助堆栈,但将迄今为止最小的元素分开。当主栈为空时,压入最小的然后所有其他元素。

例如

4 5 2 7| 

4 5 2| : 7
4 5|7  : 2
4|5 7  : 2
|4 5 7 : 2

2|4 5 7 
2 4|5 7
2 4 5|7
2 4 5 7|

【讨论】:

【参考方案4】:

由于挑战提到“递归”,看起来您应该在排序时使用调用堆栈(和堆栈帧)来保存数据。

我会建议一种选择排序算法,其中堆栈有一个未排序,上部和一个已排序下部。一开始,未排序的部分是整个堆栈。然后进行 n 次迭代,在每次迭代中,我们找到未排序部分中的最大值并将其移动到已排序部分的顶部。

更详细地说,在每次迭代中,我们都会执行以下步骤:

递归弹出值,并跟踪遇到的最大值。在每次递归调用时记住当前值是否大于目前发现的最大值。

在未排序部分的底部,推入最大值并停止递归。这使得函数退出时的堆栈大小比进入时大 1。

在退出递归调用时,如果当前值是迄今为止最大的递归值,则检查堆栈是否仍然大于预期:

如果是这样,这意味着该值确实是全部最大值,并且它不应该被推入堆栈再次,因为它被放在了底部。通过不再次推送它,堆栈大小现在在退出时与进入时相等。 如果不是这样,这意味着在递归树的更深处发现了一个更大的值,并且应该再次将当前值推入堆栈。

如果当前值不是迄今为止最大的递归值,则只需推回该值。

在此阶段之后,我们将最大值移至堆栈底部。现在将堆栈的“底部”定义为高一个条目,以便保持找到的最小值不变。重复上述步骤,直到达到新的“底部”。

继续像这样提升底部,直到底部与堆栈顶部匹配。这表明堆栈已完全排序。

这是一个 javascript 实现:

function moveMaxDown(stack, bottom, maxValue) 
    let value = stack.pop();
    let len = stack.length; // Memorize length before recursing
    if (len > bottom)  // Not reached the bottom yet
        if (value <= maxValue) 
            moveMaxDown(stack, bottom, maxValue);
         else 
            moveMaxDown(stack, bottom, value);
            if (stack.length > len) return; // Current value was already inserted
        
     else 
        if (value <= maxValue) stack.push(maxValue); // Extra push
    
    stack.push(value);


function stackSort(stack)         
    for (let bottom = 0; bottom < stack.length; bottom++) 
        moveMaxDown(stack, bottom, -Infinity);
    
    return stack;


// demo
console.log(stackSort([3, 2, 1]));
console.log(stackSort([11, 2, 32, 3, 41]));

【讨论】:

以上是关于排序堆栈的算法的主要内容,如果未能解决你的问题,请参考以下文章

在最佳情况下,由于堆栈溢出错误,快速排序算法失败 - C++

“就地”MSD 基数排序、堆栈空间和堆栈溢出

使用结构对两个堆栈进行排序 - 编译错误

算法总结——堆栈

拓扑排序算法实现

前端算法相关