繁体   English   中英

堆栈递归实现的复杂性

[英]Stack Recursive Implementation Complexity

我大学的老师曾教过我们堆栈的实现。 但这是完全递归的,在网络上的任何地方我都没有看到这样的东西。 所以我想知道这有多好或有效率。 正如我所看到的,许多使用链表(成为最有效的方法)并使用数组的堆栈的实现。

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;
    }
}

拜托,我想听听您的意见,因为我真的没有其他地方看到过这种实现。 请随时解释其复杂性!

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

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

复杂度优先:

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

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

比较复杂度:

  • 最佳情况下的时间复杂度与数组实现中的相同: O(1)

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

  • 平均和最坏情况下的复杂度的比较有点棘手,因为基于数组的度量取决于堆栈是否随着堆栈的增长和缩小而重新分配。 那是特定于实现的。

比较性能(最佳情况):

  • 使用链表版本进行push会更加昂贵,因为每个push调用都会创建一个新对象。 (对于基于阵列的版本,最好的情况是阵列中有一个空闲插槽……因此不需要重新分配。)

  • 弹出会间接地增加成本,因为它会导致对象无法到达。

  • 对于基于列表的实现,最佳情况下的空间使用肯定更大。 堆栈条目由具有2个引用的对象表示。 那就是2个“单词”加上对象标题加上填充。 在64位JVM中...可能为24个字节。 相比之下,基于数组的解决方案在数组中为每个条目使用1个引用... 8个字节...。

由于上述原因,一般情况和最坏情况下的性能和空间使用情况很难进行比较。

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

(实际上,那里有一个错误!如果您尝试将null推送,它会“工作”,但是然后Stack.isEmpty()将报告堆栈为空。如果您尝试推送nullpush方法应该引发异常。 ..或至少保护数据结构。)


请随时解释其复杂性!

如果自己解决问题,您将学到更多。

但这是完全递归的...

值得商榷。 从某种意义上说,数据结构是递归的,但是算法不需要递归。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM