百度笔试题:用堆栈模拟队列功能


有这样一道百度笔试题:


请使用堆栈(Stack)来模拟队列(FIFO)功能,要求数据必须储存在堆栈内部。需要实现enqueue(入队)、dequeue(出队)、isEmpty(判空)3个功能。


【解   析】 图1 所示,用栈 S1 S2 来模拟队列。


 
     S1                    S2


假定输出序列为 Y ,对于 n 个元素的输入序列 X ,若按照如下过程进行操作:


①X中元素按序全部顺序进入S1中;


②依次将S1中元素出栈并压入S2栈中,直到S1栈空为止;


③依次将S2中元素出栈并送输出序列Y,直到S2栈空为止。


则输出序列的顺序与输入序列X完全相同,符合队列先进先出的特点。进一步分析可知,若将X从左向右分成若干段,按从左到右的顺序对每个段作上述操作,亦可得到同样的结果。所以,用两个栈模拟队列三个功能的操作过程可描述如下:


① enqueue(入队):入队元素直接放入S1栈中(Push)。


② dequeue(出队):若S2栈不为空,则取S2栈的栈顶元素(Pop)作为出队元素;否则将栈S1中元素全部搬到S2中,再取S2栈的栈顶元素(Pop)作为出队元素(这可视为将入队元素分段地通过S1和S2栈)。


③ isEmpty(判空):若S1和S2两个栈均为空,则队列为空;否则不为空。


【参考程序】


Stack  *S1, *S2;   // S1和S2是两个栈

int  QIsEmpty ( )   // 判队空

{     if( IsEmpty ( S1 ) && IsEmpty ( S2 ) )  return 1;     //IsEmpty是判栈空的函数

      else return 0;

}

void  EnQueue ( int n )   // 入队

{     Push( S1, n );

}

int  DeQueue ( )             //出队

{     if( IsEmpty ( S2 ) ) {

               while( !IsEmpty ( S1 ) ) {

                         Push( S2, Pop( S1 ) );

               }

      }

      if( IsEmpty ( S2 ) )  return -1;

      else return  Pop ( S2 );

}


栈的定义及操作实现的参考代码如下所示。


typedef struct Node

{     int data;

      structNode  *next;

} Node, Stack;

Stack *CreateStack ( )

{     Node *p, *x;

      x= ( Node * ) malloc ( sizeof ( Node ));

      x->data= 0;

      x->next= NULL;

      p= x;

      return p;

}

int  IsEmpty ( Stack  *S )

{     if( S->next != NULL )  return  0;

      else return  1;

}

void  Push ( Stack  *S,  int n )

{     Node *x;

      x= ( Node * ) malloc ( sizeof ( Node ));

      x->data= n;

      x->next= S->next;

      S->next= x;

}

int  GetTop ( Stack  *S )

{     if( !IsEmpty ( S ))  return  S->next->data;

      else return  0;

}

int  Pop ( Stack  *S )

{     Node *p;

      if( !IsEmpty ( S )) {

               p= S->next;

               S->next= S->next->next;

               return p->data;

               }

      else

               return 0;

}


【拓  展】修改本题的已知条件,使用两个队列来模拟一个栈,队列的容量足够大,该如何解决呢?


设用来模拟栈s的队列是q1和q2。队列和栈的操作如表1所示。


表1队列和栈的操作


操作

函数名

含义

队列

入队

enqueue( q, x )

元素x入队q中

出队

dequeue( q )

从q中出队一个元素

判空

IsEmpty( q )

判断队q是否为空

入栈

push(  s, x )

元素x入栈s中

出栈

pop(  s )

从s中出栈一个元素

判空

IsEmpty( s )

判断栈s是否为空


使用伪代码描述栈s的操作如下:


push ( s, x )

{     enqueue( q1, x );    // q1为主队列,q2为辅助队列

}

pop ( s )

{     while(!IsEmpty ( q1 ))

      {        y = dequeue ( q1 );

               if  ( !IsEmpty ( q1 ))

                         enqueue( q2, y );  

   // 队列q1中的元素入队列q2中

               else      // y是队列q1中最后入队的元素

               {        while ( !IsEmpty ( q2 ) )

                               enqueue( q1, dequeue ( q2 )); 

// 将q2中的所有元素写回q1中

                         returny;

               }

      }

}

IsEmpty ( s )

{     return  ( IsEmpty ( q1 ));

}


每当要从栈s中出栈一个元素时,都要将队列q1中的所有元素(除最后入队元素外)移至辅助队列q2中。然后将q1中的最后一个元素出队作为出栈元素。出栈后,还要将元素从q2中移回q1中。时间开销很大。


可以增加一个奇偶标志flag以避免元素的过多移动。两个队列轮流当主队列及辅助队列。只需在出栈前将元素从一个队列移到另一个队列,出栈后不需要再将元素移回。但由于保存元素的队列是变化的,故根据flag值来判定当前操作是对q1进行的,还是对q2进行的。


本文已收录于《横扫Offer--程序员招聘真题详解700题》一书,开点工作室著,清华大学出版社,该书目前已编写修改完成,7月即将上市。更多程序员笔试面试真题的精彩详解请参见该书。

全部评论
大王,能不能早点出啊,千万不要搞得校招都结束了,再出哦.
点赞
送花
回复
分享
发布于 2016-07-21 18:24

相关推荐

点赞 26 评论
分享
牛客网
牛客企业服务