【算法编程】用栈实现另一个栈的排序

  给定一个栈,对其进行排序,使得栈顶至栈底的为降序,只能申请一个栈和变量,不能使用数组或多余的栈等数据结构.
  试题来源:Coding Interviewing Guided (Page 12)
  难度:★★★☆☆


思路一

C++源码:

//用一个栈实现另一个栈的排序
//给定一个栈,对这个栈进行排序,使得栈顶至栈底的元素为降序排列,注意,只允许创建另一个栈,或相关的变量,不能使用数组等数据结构
#include <iostream>
#include <stack>
using namespace std;

void sort_stack_by_stack(stack<int> &s){
stack<int> s2;
int ans = s.size();//表示栈s从栈顶到栈底第ans元素之后都是有序的
while(ans>0){
int min = s.top();//用于记录当前无序部分最小的值
int min_num = 1;//用于记录最小值的个数
//先对栈s进行出栈,且每次出栈时将元素入栈s2,并记录最小值
for(int i=0;i<ans;++i){
int top = s.top();
s.pop();
s2.push(top);
if(top<min){
min = top;
min_num = 1;
}else if(top==min) min_num++;
}
for(int i=0;i<min_num;i++) s.push(min);//将最小值先入栈s
while(!s2.empty()){//将剩余的值入栈s,
if(s2.top()!=min) s.push(s2.top());
s2.pop();
}
ans-=min_num;//且更新有序的范围
}
}

int main(){
int v[9] = {6,3,7,2,4,6,0,9,5};
stack<int> s;
for(int i=0;i<9;i++){//初始化一个栈
s.push(v[i]);
}
sort_stack_by_stack(s);
cout<<"\nsorted stack pop order:\n";
while(!s.empty()){
int top = s.top();
s.pop();
cout<<top<<' ';
}
system("pause");
return 0;

}

原理讲解:

  假设给定的栈为s,另一个开辟的栈为s2,s2可以作为临时存放s元素的位置,设定一个阈值ans,初始化为元素的个数,其表示在栈s中,从栈顶到底ans个元素是无序的,而第ans个元素一直到栈底是有序的,因此我们只需要不断地将ans减少到0,每次减少时将无序中的最小值如栈s中即可。整个过程可以分为下面几步:

  • step1:先将给定栈s中所有元素出栈并入栈到s2中,并统计最小值及出现的次数;
  • step2:s为空时,此时所有元素已转移到s2中,且获得了当前最小值min及其个数min_num;
  • step3:将这个最小值按照其个数重复入栈s中,即将最小值先入栈s;
  • step4:再次将s2中的元素出栈并入栈到s中,其中在s2出栈时,如果当前元素是最小值,则忽略;
  • step5:ans-=min_num,重复执行上面步骤,知道ans==0。

思路二

  上面的方法有一个问题,就是入栈出栈次数太多,因此还有一种思路,即每次从栈s中出栈一个元素a,并判断其与s2的栈顶元素b的大小,如果a小于等于b,则入栈到s2,否则对s2进行出栈并入栈到s中,直到s2的栈顶元素恰巧比a小时,将a入栈s2,重复上述步骤直到s为空,此时s2由栈顶至栈底是升序的,将s2依次出栈入栈到s中即可。

将上述的代码中函数sort_stack_by_stack进行修改:

void sort_stack_by_stack(stack<int> &s){
stack<int> s2;
while(!s.empty()){
int top = s.top();
s.pop();
if(s2.empty() || top <= s2.top()) s2.push(top);
else {
while(!top.empty() && top<=s2.top()){
s.push(s2.top());
s2.pop();
}
s2.push(top);
}
}
while(!s2.empty()){
s.push(s2.top());
s2.pop();
}
}