THU数据结构编程作业一:隧道(Tunel)

来源:互联网 发布:手机卫士源码 编辑:程序博客网 时间:2024/06/13 08:04

本题主要解决的问题:
常数时间复杂度范围内获得栈的最大值;
用两个栈模拟一个队列。
细节问题:scanf 和 getchar 获取输入的问题。
问题描述
现有一条单向单车道隧道,每一辆车从隧道的一端驶入,另一端驶出,不允许超车。该隧道对车辆的高度有一定限制,在任意时刻,管理员希望知道此时隧道中最高车辆的高度是多少。
现在请你维护这条隧道的车辆进出记录,并支持查询最高车辆的功能

输入
第一行仅含一个整数,即高度查询和车辆出入操作的总次数n

以下n行,依次这n次操作。各行的格式为以下几种之一:

1. E x      //有一辆高度为x的车进入隧道(x为整数)2. D        //有一辆车离开隧道3. M        //查询此时隧道中车辆的最大高度

输出
若D和M操作共计m次,则输出m行
对于每次D操作,输出离开隧道车辆的高度
对于每次M操作,输出所查询到的最大高度

样例
Input

9E 5E 6ME 2MDMDM

Output

665662

限制
0 ≤ n ≤ 2,000,000
0 ≤ x ≤ 2^31 - 1
保证车辆的进出序列是合法的
时间:2 sec
空间:256 MB

提示
如何由多个栈来模拟一个队列?可参考第四章末尾的某习题。
如何实现一个能够高效获取最大值的栈?
如何实现一个可以高效获取最大值的队列?
可参考第04章XA节的讲义以及《习题解析》的[10-19]题、[10-20]题.


先上上源代码:

#include<cstdio>#include<cstdlib>using namespace std;//fast ioconst size_t sz = 1 << 20;struct fastio{    char inbuf[sz];    char outbuf[sz];    fastio(){        setvbuf(stdin, inbuf, _IOFBF, sz);        setvbuf(stdout, outbuf, _IOFBF, sz);    }}io;//maximum tunel lengthconst size_t max_sz = 2000010;//simulate a queue by two stackslong stack_push[max_sz];long stack_pop[max_sz];//simulate two pointers for pop and push operationslong stack_push_pointer(0),stack_pop_pointer(0);//store max value for two stackslong stack_push_max(0), stack_pop_max(0);//push elements into enqueue stackvoid stack_push_push(long e){    //store the difference of element and maxvalue    stack_push[++stack_push_pointer] = e - stack_push_max;    //if the stored elements is negative, the max value should be the new element    if(stack_push_max < e)                          stack_push_max = e;}//pop elements to the dequeuing stack to be dequeuedlong stack_push_pop(){    if(stack_push_pointer < 1){        printf("STACK_PUSH POP ERROR!\n");        return 0;    }    long e;    //if the poping element is not negative, the top element is the maxvalue    //then the maxvalue should be changed.    if(stack_push[stack_push_pointer] >= 0){        e = stack_push_max;        stack_push_max = stack_push_max - stack_push[stack_push_pointer];    }else        e = stack_push_max + stack_push[stack_push_pointer];//recover the oroginal value    --stack_push_pointer;    return e;}//push elements into dequeuing stack and record the max valuevoid stack_pop_push(long e){    stack_pop[++stack_pop_pointer] = e - stack_pop_max;    if(stack_pop_max < e)                           stack_pop_max = e;}//dequeue from the dequeuing stack long stack_pop_pop(){    if(stack_pop_pointer < 1){        printf("STACK_POP POP ERROR!\n");        return 0;    }    long e;    if(stack_pop[stack_pop_pointer] >= 0){        e = stack_pop_max;        stack_pop_max = stack_pop_max - stack_pop[stack_pop_pointer];    }else        e = stack_pop_max + stack_pop[stack_pop_pointer];    --stack_pop_pointer;    return e;}int main(){    //redirect IO#ifndef _OJ_    freopen("input.txt", "r", stdin);    freopen("output.txt", "w", stdout);#endif      long op_size;//operation times;    scanf("%ld", &op_size);    getchar();    char com_char;//command character    long com_int;//command parameter    long temp;    while(op_size-- > 0){        do{            com_char = getchar();        }while(com_char != 'E' && com_char != 'D' && com_char != 'M');//      scanf("%c", &com_char);//get command character//      if(com_char == 'E')//if enqueue, read the height of vehical//          scanf("%ld", &com_int);//      getchar();        switch(com_char){            case('E'):                scanf("%ld", &com_int);                stack_push_push(com_int);                           break;            case('D'):                if(stack_pop_pointer == 0){                    for(long i = stack_push_pointer; i > 0; --i)                        stack_pop_push(stack_push_pop());                }                temp = stack_pop_pop();                printf("%ld\n", temp);                break;            case('M'):                temp = stack_push_max >= stack_pop_max ? stack_push_max : stack_pop_max;                printf("%ld\n", temp);                break;            default:                break;        };    }    return 0;}

首先需要说明的是上面程序的设计并不是很好,完全没有用到类的设计,以及用了很多全局变量,这只是出于提高程序运行速度考虑,整个算法应该是没有问题的。
本题主要有两个问题:

  1. 求栈的最大值问题,

  2. 如何用两个栈模拟一个队列。

求栈最大值问题
问题描述

一个整数栈stack,具有push和pop操作,其时间空间复杂度皆为O(1)。
设计算法max操作,求栈中的最大值,该操作的时间空间复杂度也要求为O(1)。
可以修改栈的存储方式,push,pop的操作,但是要保证O(1)的时间空间复杂度。

算法描述

变量Max保存当前最大元素值,初始值为最小整数m。
1. 当push入栈时,将(当前元素-Max)存入栈中, 若当前元素小于Max,栈中元素为负数; 若当前元素大于等于Max,栈中元素为非负数,将Max替换为当前元素。
2. 当pop出栈时, 若栈中元素为负数,则将(栈中元素+Max)弹出栈; 若栈中元素为非负数,则将Max弹出栈,并将Max替换为(Max-栈中元素)。
3. Max即为当前栈中最大元素值。

主要思路是将最大值以某种方式在原有栈中标记出来,从而减少空间使用。可以用正负数来区分普通元素和最大值元素:
普通元素使用负数存储(元素-Max);
最大值元素使用非负数存储(New Max - Old Max);
这样便可在栈中区分普通元素和最大值元素,并可通过Max恢复Old Max。

以上算法分析内容源自: 面试题——栈的最大值问题
假设入栈序列为:3,1,2,5,7,4,6,假设原栈顶元素为 0,原Max = 0:
这里写图片描述

这里写图片描述
上图,元素3-Max,即 3-0 = 3,首先入栈,因为 3>0,所以Max变成3,;随后,1 -Max,即1-3=-2,压入栈,,-2<3, 所以Max不变依然为3,元素2 同理。

这里写图片描述
上图,元素5,将5-Max,即5-3=2,压入栈,因为2>0,所以同时将Max变成5;

这里写图片描述
上图,元素7,将7-Max,即7-5=2压入栈,同时将Max变成7;
这里写图片描述
上图元素4,6同理入栈。
这里写图片描述
上图,对于元素6,因为栈顶元素小于0,所以出栈是Max不变,并将出栈元素恢复为原来的值,-1+Max,即-1+7 =6.出栈,同理元素4 出栈。
这里写图片描述
上图,元素7,因为栈顶元素大于0,所以判断当前栈顶元素为栈的最大值Max,即为7,当栈顶弹出后Max应该改变,即Max = Max - 2= 7 - 2 =5;
这里写图片描述
上图,元素5,同理,因为栈顶元素大于0,所以判断当前应该弹出的栈顶元素等于Max,即 5,同时Max= Max - 2=5-2=3;
这里写图片描述
上图,再次弹出栈顶时因为栈顶元素小于0,所以Max不变,弹出当前栈顶的值加上Max,即为2,同理弹出元素 1。

最终全栈只剩下元素3,Max = 3。

用两个栈模拟一个队列
原理如下图所示:
这里写图片描述
本程序用两个数组来模拟两个栈,然后将这两个栈模拟成一个队列。push操作是将元素压入stack_push中,在执行pop操作时首先判断stack_pop是否为空,如果为空则将stack_push中的所有元素依次弹出并压入到stack_pop栈中以待pop操作。同时,对于这两个栈在各自的pop和push操作时都分别记录自己的Max(stack_push_max 和 stack_pop_max),而两者的最大值即为整个队列的最大值。

以上就解决了程序的主要两个问题。

另外在调试时遇到了输入和输出的问题,即在读取命令是注释的那部分程序是最初的读入代码后来在OJ上调试总是有三个过不了。调试了很久,代码也反复检查了很久,最后将那部分读命令的程序改了以后就100%通过了。scanf 和getchar 获得输入而引发的问题貌似常常会出现。

0 0
原创粉丝点击