部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

编程之美--3.7队列中取最大值操作问题

 参考资料:
http://www.cnblogs.com/pangxiaodong/archive/2011/09/10/2172833.html
http://blog.csdn.net/linyunzju/article/details/7765324

 

问题:

假设有这样一个拥有3个操作的队列:
  1. EnQueue(v):将v加入队列中
  2. DeQueue:使队列中的对首元素删除并返回此元素
  3. MaxElement:返回队列中的最大元素
请设计一个数据结构和算法,让MaxElement操作的时间复杂度尽可能的低。

 

解法1:(不正确)在队列的数据结构中添加一个MaxVal变量,每次EnQueue(v),就将元素和MaxElement进行比较。但是存在问题是,当值为最大的元素出队时,无法判断现在最大的元素。如果想正确得到MaxVal,在每次最大元素出队的时候,都要重新判断一次最大元素。

解法2:采用最大堆。用最大堆来维护队列中的节点,队列用单链表表示,每个节点包含数据,而最大堆用数组表示,数组元素为节点的指针。入队和出队的时间复杂度为O(logn),取最大值的时间复杂度为O(1)。

解法3:用两个栈来当做队列。
两个栈的方法:
    A栈,B栈
    取最值:返回A栈的最值和B栈的最值相比后的最值。复杂度O(1)。
    入队操作:直接入到B栈中。复杂度O(1)。
    出队操作:如果A栈不为空,直接A栈出栈,复杂度为O(1),如果A栈为空,那么将B栈内容逐个出栈并且逐个入栈到A中,然后A栈出栈,复杂度O(N),实际上是B栈的长度。

因此这个问题的关键在于如何设计栈的数据结构和操作函数。

队列类,利用了两个栈构成,操作方法在前面已经叙述。

class Queue{ //使用两个栈构成的队列
    private Stack stackA;
    private Stack stackB;
    
    public Queue(){
        this.stackA = new Stack();
        this.stackB = new Stack();
    }
    
    public int MaxVal(){ //先获得stackA和stackB两个栈各自的最大值,这二者的最大值就是队列的最大值
        int x = stackA.getMax();
        int y = stackB.getMax();
        return x>y?x:y;
    }
    
    public void enQueue(int element){
        stackB.push(element);
    }
    
    public int deQueue(){
        if(stackA.isEmpty()){
            while(!stackB.isEmpty()){
                stackA.push(stackB.pop());
            }
        }
        return stackA.pop(); 
    }
    
    public boolean isEmpty(){
        if(stackA.isEmpty()&&stackB.isEmpty())
            return true;
        else return false;
    }
}

 

栈类:入栈和出栈都经过了改造

class Stack{
    private int MAXN= 20; //设定一个栈元素最多为20个
    private int[] stackItem; //存放栈内元素
    private int stackTop;    //指示栈顶
    private int[] link2NextMax;    //存放下一个最大值的index,实际上为下标从0到栈顶前一个元素的最大值,方便当前元素出栈后找到最大值
    private int maxStackItemIndex;  //最大值的index
    
    public Stack(){
        stackTop = -1;
        maxStackItemIndex = -1;
        stackItem = new int[MAXN];
        link2NextMax = new int[MAXN];
    }
    
    public void push(int x){
        stackTop++;
        if(stackTop>MAXN){
            System.out.println("栈超过最大容量");
            return;
        }
        else{
            stackItem[stackTop]=x;
            if(x>getMax()){
                link2NextMax[stackTop]=maxStackItemIndex; //保存之前的最大值所在位置的下标
                maxStackItemIndex = stackTop;    //更新最大值位置的下标
            }
            else{
                link2NextMax[stackTop]=-1;
            }
        }
    }
    
    public int pop(){
        int result = Integer.MIN_VALUE ;
        if(stackTop<0)
            System.out.println("没有元素了");
        else{
            result = stackItem[stackTop];
            if(stackTop==maxStackItemIndex){
                maxStackItemIndex=link2NextMax[stackTop];
            }
            stackTop--;
        }
        return result;
    }
    
    public int getMax(){
        if(maxStackItemIndex>=0)
            return stackItem[maxStackItemIndex];
        else
            return Integer.MIN_VALUE;
    }
    
    public boolean isEmpty(){
        if(stackTop==-1) //栈空
            return true;
        else return false;
    }
}

 

main()

public class MyGetMax {
    public static void main(String args[]){
        Queue myQue = new Queue();
        myQue.enQueue(6);
        myQue.enQueue(1);
        myQue.enQueue(9);
        myQue.enQueue(7);
        myQue.enQueue(4);
        myQue.enQueue(5);
        myQue.enQueue(0);
        myQue.enQueue(2);            
        
        while(!myQue.isEmpty()){            
            System.out.print("当前队列内最大元素为:"+myQue.MaxVal());
            System.out.println(", 出队元素为:"+myQue.deQueue());
        }
    }
}

运行结果:

当前队列内最大元素为:9, 出队元素为:6
当前队列内最大元素为:9, 出队元素为:1
当前队列内最大元素为:9, 出队元素为:9
当前队列内最大元素为:7, 出队元素为:7
当前队列内最大元素为:5, 出队元素为:4
当前队列内最大元素为:5, 出队元素为:5
当前队列内最大元素为:2, 出队元素为:0
当前队列内最大元素为:2, 出队元素为:2

 

posted @ 2015-06-28 16:52  流了个火  阅读(238)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats