【问题标题】:How to compute the algorithmic space complexity如何计算算法空间复杂度
【发布时间】:2011-04-20 05:30:37
【问题描述】:

我正在复习我的数据结构和算法分析课,我收到一个问题,如何确定merge sortquick sort 的空间复杂度 算法?

链表合并排序的递归深度仅为O(log n)

连续快速排序所需的额外存储空间量为 O(n)。

我的想法:

两者都使用分而治之的策略,所以我猜链表合并排序的空间复杂度应该和连续快速排序一样。实际上我选择 O(log n) 因为在每次迭代或递归调用之前,列表被分成两半。

感谢您的任何指点。

【问题讨论】:

    标签: algorithm data-structures complexity-theory quicksort mergesort


    【解决方案1】:

    快速排序的最坏情况递归深度不是(必然)O(log n),因为快速排序不会将数据“分成两半”,它会将数据围绕可能是或可能不是中位数的枢轴进行拆分。可以实现快速排序来解决这个问题[*],但大概 O(n) 分析是一个基本的递归快速排序实现,而不是改进的版本。这将解释您在块引用中所说的内容与您在“我的想法”下所说的内容之间的差异。

    除此之外,我认为您的分析是合理的 - 除了每个递归级别的固定数量之外,两种算法都没有使用任何额外的内存,因此递归深度决定了答案。

    我想,另一种解释差异的可能方法是 O(n) 分析是错误的。或者,“连续快速排序”不是我以前听过的术语,所以如果它并不意味着我认为它的作用(“快速排序数组”),它可能意味着快速排序在某种意义上必然是空间效率低下的,例如返回分配的数组而不是就地排序。但是,根据合并排序的递归深度与快速排序的输入副本的大小来比较快速排序和合并排序是很愚蠢的。

    [*] 具体来说,不是在两个部分上递归调用函数,而是将它放在一个循环中。对较小的部分进行递归调用,然后循环执行较大的部分,或者等效地将较大的部分(指向)推入(指向)堆栈以稍后执行,然后循环执行较小的部分。无论哪种方式,您都可以确保堆栈的深度永远不会超过 log n,因为 not 放在堆栈上的每个工作块最多是它之前的块大小的一半,下降到一个固定的最小值(如果您纯粹使用快速排序进行排序,则为 1 或 2)。

    【讨论】:

    • 我认为快速排序中选择不那么好的枢轴可能会导致差异。另一方面,“连续快速排序”是精确的“快速排序数组”,至于你实现优化,我需要阅读更多内容才能理解您表达的内容。
    【解决方案2】:

    我不太熟悉“连续快速排序”这个术语。但是快速排序可以具有 O(n) 或 O(log n) 的空间复杂度,具体取决于它的实现方式。

    如果是这样实现的:

    quicksort(start,stop) {
        m=partition(start,stop);
        quicksort(start,m-1);
        quicksort(m+1,stop);
    }
    

    那么空间复杂度是O(n),而不是通常认为的O(log n)。 这是因为你在每一层都推入堆栈两次,所以空间复杂度是由循环确定的:

    T(n) = 2*T(n/2)
    

    假设分区将数组分成 2 个相等的部分(最佳情况)。根据Master Theorem 的解决方案是 T(n) = O(n)。

    如果我们在上面的代码 sn-p 中将第二个快速排序调用替换为尾递归,那么你会得到 T(n) = T(n/2),因此 T(n) = O(log n)(根据情况2 Master定理)。

    也许“连续快速排序”指的是第一个实现,因为两个快速排序调用彼此相邻,在这种情况下空间复杂度为 O(n)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-21
      • 2015-07-25
      • 2020-04-02
      • 1970-01-01
      • 2013-11-01
      • 1970-01-01
      相关资源
      最近更新 更多