栈和队列的一些笔试题(1)

下面来写一些关于栈和队列的一些笔试题:

问题1:实现一个栈,要求实现Push(入栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)

问题2:使用两个栈实现一个队列
问题3:使用两个队列实现一个栈



问题1:实现一个栈,要求实现Push(入栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)

问题分析:

要实现返回栈的最小值的时间复杂度为O(1),就要使整个栈的最小元素一定要是在栈顶,那么返回栈的在最小元素就转化为了取栈顶元素,时间复杂度就变为了O(1)
为了实现这个目的:使整个栈的最小元素在栈顶,让入栈的时候,每次入栈两个元素,其中第一个入栈的为真正需要入栈的元素value,第二个入栈的为当前栈的最小值min,详细过程如图所示



(1)初始化操作
这个问题首先要对栈进行初始化操作
  3 typedef struct MinStack
  4 {
  5     SeqStact stack;                                                                          
  6 }MinStack;
  7 
  8 void MinStackInit(MinStack* min_stack)
  9 {
 10     if(min_stack == NULL)
 11     {
 12         //非法操作
 13         return;
 14     }
 15     SeqStactInit(&min_stack->stack);
 16 }
(2)入栈操作
如前面分析,入栈要一次插入两个元素,分别为真正要插入的元素value和当前栈的最小值min
 18 void MinStackPush(MinStack* min_stack,SeqStactType value)
 19 {
 20     if(min_stack == NULL)
 21     {
 22         //非法操作
 23         return;
 24     }
 25     SeqStactType min=value;
 26     SeqStactType top;
 27     int ret = SeqStactTop(&min_stack->stack,&top);
 28     if(ret!=0)//ret=1
 29     {
 30         //有棧顶元素对情况下,让min等于棧对最小值                                             
 31         min=top<value?top:value;
 32     }
 33 
 34     SeqStactPush(&min_stack->stack,value);//先入棧的为真正要入棧对元素
 35     SeqStactPush(&min_stack->stack,min);//后入棧对为当前棧对最小值
 36 }

(3)出栈操作
至于 出栈过程就是一次性出栈两个元素,这样栈顶元素依旧是该栈的最小
 38 void MinStackPop(MinStack* min_stack)                                                        
 39 {
 40     if(min_stack == NULL)
 41     {
 42         //非法操作
 43         return;
 44     }
 45     //连续出栈两个元素
 46     SeqStactPop(&min_stack->stack);
 47     SeqStactPop(&min_stack->stack);
 48 }
 49 

(4)取栈的最小元素
题目中要求时间复杂度为O(1),就要把最小的元素放在栈顶,前面入栈、出栈的过程已经让当前栈的最小元素处于栈顶的位置,直接取该栈的栈顶元素就完成要求了,详细见程序
 50 int MinStackTop(MinStack* min_stack,SeqStactType* value)
 51 {
 52     if(min_stack == NULL)
 53     {
 54         //非法操作
 55         return 0;
 56     }
 57     return SeqStactTop(&min_stack->stack,value);
 58 }                                                                                            
 59 

问题2:使用两个栈实现一个队列
问题分析:

栈是先入后出

队列是先进先出

要想用两个栈来实现一个队列,就是将元素的先进后出变为先进先出

首先需要创建两个栈input栈和output栈,元素先进input栈,然后再从input栈中出栈,再进入output栈,然后output栈再出栈,此时队列的顺序就为先进先出的情况了详细过程如图
(1)初始化操作

首先要进行初始化操作,就是对两个栈分别进行初始化操作

  3 typedef struct QueueBy2Stack
  4 {
  5     SeqStact input;
  6     SeqStact output;
  7 }QueueBy2Stack;
  8 
  9 void QueueInit(QueueBy2Stack* q)
 10 {
 11     if(q == NULL)
 12     {
 13         //非法操作
 14         return;
 15     }
 16     SeqStactInit(&q->input);
 17     SeqStactInit(&q->output);
 18 }

(2)入栈操作

这里的入栈是指到最后,入栈到最后面的output栈,之前还要进行对input的入栈和对input的出栈同时还要对栈中元素的一些判断

需要注意的是,元素出入栈的顺序必须是元素先入栈input栈,然后再出栈input,再入栈output,再从output出栈,当在入栈input栈的时候,要保证output栈为空,否则,再进行后面出入栈的操作的时候,栈中元素的顺序就会发生混乱,一定要将output栈中的元素全部出栈到input栈中,再进行下一步的操作,详细见程序

 20 void QueuePush(QueueBy2Stack* q,SeqStactType value)
 21 {
 22     if(q == NULL)
 23     {
 24         //非法操作
 25         return;
 26     }
 27     //若output棧不为空,则需要将output棧中的元素全部出棧到input棧中,然后再进行后续操作
 28     while(1)
 29     {
 30         SeqStactType top;
 31         int ret=SeqStactTop(&q->output,&top);
 32         if(ret == 0)//空棧                                                                   
 33         {
 34             break;
 35         }
 36         SeqStactPop(&q->output);
 37         SeqStactPush(&q->input,top);
 38        
 39     }
 40     SeqStactPush(&q->output,value);
 41     return;
 42 }
 43 

(3)出栈操作

元素出栈的顺序必须是从output栈中出栈,这就要保证在出栈的时候,input栈必须为空栈,若input栈不为空,则需要将input栈中的元素先出栈到output栈中,详细见程序

 44 void QueuePop(QueueBy2Stack* q)
 45 {
 46     if(q == NULL)
 47     {
 48         //非法操作                                                                           
 49         return;
 50     }
 51     while(1)
 52     {
 53         SeqStactType top;
 54         int ret=SeqStactTop(&q->input,&top);
 55         if(ret == 0)
 56         {
 57             break;
 58         }
 59         SeqStactPop(&q->input);
 60         SeqStactPush(&q->output,top);
 61     }
 62     SeqStactPop(&q->output);
 63 }
 64 

(4)取栈顶元素操作
取栈顶元素只是在出栈的 output 栈中取栈顶元素,操作之前要保证 input 栈为空,详细见程序
 65 int QueueTop(QueueBy2Stack* q,SeqStactType* value)
 66 {
 67     if(q == NULL || value == NULL)
 68     {
 69         //非法操作
 70         return 0;
 71     }   
 72     while(1)
 73     {
 74         SeqStactType top;
 75         int ret=SeqStactTop(&q->input,&top);
 76         if(ret == 0)
 77         {                                                                                 
 78             break;
 79         }
 80         SeqStactPop(&q->input);
 81         SeqStactPush(&q->output,top);
 82     }
 83     return SeqStactTop(&q->output,value);
 84 }

问题3:使用两个队列实现一个栈


问题分析:

栈是先入后出

队列是先进先出

要想用两个队列来实现一个栈,就是将元素的先进先出变为先进后出

首先要创建两个队列queue1queue2先将元素全部入队列到queue1中,此时queue2队列为空,再将queue1队列中的前几个元素出队列到queue2中,再将queue1中的元素取出,如此往复,最终取出的元素顺序就为出栈的顺序,详细如图所示

(1)初始化操作

将两个链表初始化,详细见程序
  3 typedef struct StackBy2Queue
  4 {
  5     SeqQueue queue1;
  6     SeqQueue queue2;
  7 }StackBy2Queue;
  8 
  9 void StackInit(StackBy2Queue* stack)                                                      
 10 {
 11     if(stack == NULL)
 12     {
 13         //非法操作
 14         return;
 15     }
 16     SeqQueueInit(&stack->queue1);
 17     SeqQueueInit(&stack->queue2);
 18 }

(2)入队操作

入队列的操作,其实就是将元素入到非空的队列中,详细见程序

 20 void StackPush(StackBy2Queue* stack,SeqQueueType value)
 21 {
 22     if(stack == NULL)
 23     {
 24         //非法操作
 25         return;
 26     }
 27     //input队列为非空队列
 28     SeqQueue* input=stack->queue1.size!=0?&stack->queue1:&stack->queue2;
 29     SeqQueuePush(input,value);
 30 }                                                                                         
 31 
(3)出队操作
出队列操作,就是将元素多的队列设为from将元素少的队列设为to队列,将from队列中的元素移动到to队列中,直到from队列中只有一个元素,详细见程序
 32 void StackPop(StackBy2Queue* stack)
 33 {
 34     if(stack == NULL)
 35     {
 36         //非法操作
 37         return;
 38     }
 39     if(stack->queue1.size==0&&stack->queue2.size==0)
 40     {
 41         //空队列
 42         return;
 43     }
 44     //元素多对队列为from队列,即要移动的队列                                              
 45     //元素少对队列为to队列,即要移动到的队列
 46     SeqQueue* from=NULL;
 47     SeqQueue* to=NULL;
 48     if(stack->queue1.size>0)
 49     {
 50         from=&stack->queue1;
 51         to=&stack->queue2;
 52     }
 53     else
 54     {
 55         from=&stack->queue2;
 56         to=&stack->queue1;
 57     }
 58     //把from中的元素移动到to队列中,直到from中只有一个元素
 59     while(1)
 60     {
 61         if(from->size==1)                                                                 
 62         {
 63             break;
 64         }
 65         SeqQueueType value;
 66         SeqQueueFront(from,&value);
 67         SeqQueuePop(from);
 68         SeqQueuePush(to,value);
 69     }
 70     SeqQueuePop(from);
 71                                                                                           
 72 }
 73 

(4)取队首元素操作

前面同出队列操作,只是在最后取了队首元素,详细见程序

 74 int StackTop(StackBy2Queue* stack,SeqQueueType* output_value)
 75 {
 76     if(stack == NULL || output_value == NULL)
 77     {
 78         //非法操作                                                                        
 79         return 0;
 80     }
 81     
 82     if(stack->queue1.size==0&&stack->queue2.size==0)
 83     {
 84         //空队列
 85         return 0;
 86     }
 87     SeqQueue* from=NULL;
 88     SeqQueue* to=NULL;
 89     if(stack->queue1.size>0)
 90     {
 91         from=&stack->queue1;
 92         to=&stack->queue2;
 93     }
 94     else
 95     {
 96         from=&stack->queue2;
 97         to=&stack->queue1;
 98     }
 99     while(1)
100     {
101         if(from->size==1)
102         {
103             break;                                                                        
104         }
105         //SeqQueueType value;
106         SeqQueueFront(from,output_value);
107         SeqQueuePop(from);
108         SeqQueuePush(to,*output_value);
109     }
110     return 1;
111 }
112 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值