用于在java中维护堆栈的算法

时间:2012-09-28 06:15:33

标签: java collections

如何维护堆栈,以便每当从堆栈弹出时,您知道堆栈中的最小元素?该算法应具有恒定的复杂度

提前致谢

3 个答案:

答案 0 :(得分:3)

好的,这就是你需要做的......

您需要维护一些data structure包含您插入的每个元素的信息,插入该元素时的minimumsecond minimum值是什么。

所以,你想要这样的信息: -

对于推送的每个元素 - >

  • 插入后的最小值
  • 插入前的最小值

当您从堆栈中pop该元素时,将需要此信息。所以,您会知道,您是否popping最小值...如果是,那么您可以替换在推送此元素之前,minimum的当前minimum value值。如果没有,则此时minimum值不会发生变化..

例如: -

假设您当前在堆栈中有以下元素: -

[3, 5, 7, 9, 2, 4]
  • 然后按值8 ..然后你有两个值要维护.. (推出8之前的最小值,即2,以及8之后的miminum值 插入,即2): -

    min_value_before_push = min(stack)
    push 8
    min_value_after_push = min(stack)
    
  • 如果您按值1 ,则minimum_before_insertion为2, 并且minimum_after_insertion是1: -

    min_value_before_push = 2
    min_value_after_push = 1
    

现在你的筹码是: -

[1, 8, 3, 5, 7, 9, 2, 4]

现在,如果您 pop ,您会看到 value 1 : -

    min_value_before_push = 2
    min_value_after_push = 1

因此,弹出将改变最小值,因此,您更改当前最小值minimum_value_before_push为1 ..所以,您的最小值再次为2 ..

您当前的筹码变为: -

[8, 3, 5, 7, 9, 2, 4]

现在,让我们检查此算法是否适用于duplicate元素: -

假设您想再次推送value 2 ..

min_value_before_push = 2
min_value_after_push = 2

然后你继续pop,你看到value 2min_value_after_push是2,所以这意味着弹出它会改变最小值..所以你用这个值替换min_value_before_push,也是2 ..这就是我们想要的......

注意: - 此算法的一个好处是,您不需要进行太多比较..只需在推送时与current_minimum_value进行比较..并与{进行比较当您current_minimum_value ..

时{1}}

您可以尝试继续思考pop可以拥有什么......

答案 1 :(得分:2)

免责声明:禁止使用空值(就像ArrayDeque一样),并且未经过严格测试。

import java.util.ArrayDeque;

public class PessimisticStack<T extends Comparable<? super T>> {

    private class Entry {
        private Entry(T t, T minNow) {
            this.t = t;
            this.minNow = minNow;
        }
        private final T t;
        private final T minNow;
    }

    private final ArrayDeque<Entry> deque;

    public PessimisticStack() {
        deque = new ArrayDeque<Entry>();
    }

    public PessimisticStack(int initialCapacity) {
        deque = new ArrayDeque<Entry>(initialCapacity);
    }

    public void push(T t) {
        if (t == null) throw new NullPointerException();
        Entry entry = null; 
        if (deque.isEmpty()) {
            entry = new Entry(t, t);
        }
        else {
            T prevMinimum = deque.peek().minNow;
            T newMinimum = null;
            if (t.compareTo(prevMinimum) < 0) {
                newMinimum = t;
            }
            else {
                newMinimum = prevMinimum;
            }
            entry = new Entry(t, newMinimum);
        }
        deque.push(entry);
    }

    public T pop() {
        return deque.pop().t;
    }

    public T getMinimum() {
        Entry entry = deque.peek();
        return (entry == null ? null : entry.minNow);
    }
}

使用示例

PessimisticStack<String> stack = new PessimisticStack<String>();

stack.push("Zebra");
stack.push("Elephant");
stack.push("Bryan");
stack.push("Adam");
stack.push("Calvin");

String calvin = stack.pop();

// "Adam"
System.err.println(stack.getMinimum());

stack.push("Aaron");

// "Aaron"
System.err.println(stack.getMinimum());

String aaron = stack.pop();

// "Adam"
System.err.println(stack.getMinimum());

String adam = stack.pop();

// "Bryan"
System.err.println(stack.getMinimum());

答案 2 :(得分:1)

在推送元素minStack时使用另一个堆栈,比如val,检查是否val < minStack.peek(),如果是,请同时将val推送到minStack;当从stack弹出时,请检查值pop,例如pop_val,如果minStack.pop()则执行pop_val == minStack.peek()

既然我们有一个minStack可以将所有local-min-element保留在特定的时间点(直到下一次推送到minStack的时候),我们可以很容易地找出何时从minStack弹出通过检查堆栈的顶部是否为local-min-element,已经在上面介绍过了。

但是,只有当所有元素彼此都是唯一的时,该方法才能正常工作,否则,它会更难做,提示,使用计数器:)。