堆栈递归实现复杂性

时间:2014-02-15 01:35:43

标签: java recursion stack

我在大学的老师教我们这个堆栈的实现。但这个是完全递归的,我在网上的任何地方都没有看到这样的东西。所以我想知道这是多么好或有效。正如我已经看到很多带有链接列表的堆栈(最有效的)和使用数组的实现。

public class Stack<T>
{
    private T top;
    private Stack<T> base;

    public Stack(){
        top = null;
        base = null;
    }

    public Stack(T data, Stack<T> base){
        top = data;
        this.base = base;
    }

    public boolean isEmpty(){
        return top == null;
    }

    public T top(){
        return top;
    }

    public T push(T data){
        if (isEmpty()){
            top = data;
            base = new Stack<T>();
        } else {
            base = new Stack<T>(top, base);
            top = data;
        }
        return data;
    }

    public T pop(){
        T res = null;
        if (!isEmpty()){
            res = top;
            top = base.top;
            base = base.base;
        }
        return res;
    }
}

我想听听你的意见,因为我真的没有看到任何其他的这种实施。请随意解释复杂性!

1 个答案:

答案 0 :(得分:1)

正如其他人所评论的那样,这个实现使用单链表,而典型的实现使用数组来保存堆栈。

  

所以我想知道这是多么好或有效。

首先是复杂性:

  • 最佳/平均/最差情况时间复杂度为O(1)

  • 最佳/平均/最差情况下的空间复杂度为O(N)

比较复杂性:

  • 最佳案例时间复杂度与数组实施相同:O(1)

  • 最佳情况下的空间复杂度在数组实现中是相同的:O(N)

  • 平均和最坏情况复杂性的比较有点棘手,因为基于数组的度量取决于堆栈的数组是否/如何在堆栈增长和收缩时重新分配。这是特定于实现的。

比较表现(最佳情况):

  • 推送链表版本更加昂贵,因为每次push调用都会创建一个新对象。 (在基于阵列的版本的最佳情况下,阵列中有一个空闲插槽......因此不需要重新分配。)

  • Popping间接成本更高,因为它导致对象无法访问。

  • 基于列表的实现的最佳空间使用率肯定更高。堆栈条目由具有2个引用的对象表示。这是2&#34;字&#34;加上对象标题加上填充。在64位JVM中......可能是24个字节。相比之下,基于阵列的解决方案在数组中使用1个引用...每个条目使用8个字节....

由于上述原因,难以比较平均和最差情况下的性能和空间使用情况。

从API设计的角度来看:API提供了一个非泄漏的抽象。我唯一的狡辩是弹出一个空堆栈应该一个错误。如果调用方未测试意外(或预期)pop()结果,则返回null的{​​{1}}方法可能会导致问题(NPE)。此外,您无法将null放入堆栈。

(实际上,那里有一个错误!如果你试图推送一个null,那么&#34;工作&#34;,然后null会报告堆栈是空的如果您尝试推送Stack.isEmpty() ...或至少保护数据结构,push方法应该抛出异常。)

  

请随时解释复杂性!

如果您自己动手,您将了解更多信息。

  

但这个是完全递归的......

有争议的。数据结构在某种意义上是递归的,但算法并不需要递归。