归并排序时间和空间复杂度

2023-12-24

我们以合并排序的实现为例

void mergesort(Item a[], int l, int r) {
if (r <= l) return;
int m = (r+l)/2;
mergesort(a, l, m);   ------------(1)
mergesort(a, m+1, r); ------------(2)
merge(a, l, m, r);

a) 该归并排序的时间复杂度为O(n lg(n))。并行化(1)和(2)会带来任何实际收益吗?从理论上讲,在并行化它们之后,你最终也会得到O(n lg(n))。但实际上我们能得到什么收获吗?

b) 这里的归并排序的空间复杂度是O(n)。但是,如果我选择使用链表执行就地合并排序(不确定是否可以合理地使用数组完成),空间复杂度会变成O(lg(n)),因为您必须考虑递归堆栈帧大小? 我们可以治疗吗O(lg(n))作为常数,因为它不能超过 64?我可能在几个地方误解了这一点。 64到底有什么意义呢?

c) 排序算法比较 - Cprogramming.com http://www.cprogramming.com/tutorial/computersciencetheory/sortcomp.html说合并排序需要使用链表的恒定空间。如何?他们治疗了吗O(lg(n))持续的?

d) 添加以获得更多清晰度。对于空间复杂度计算,假设输入数组或列表已经在内存中是否公平?当我进行复杂性计算时,我总是计算除了输入已占用的空间之外我将需要的“额外”空间。否则空间复杂度永远是O(n)或者更糟。


归并排序时间复杂度是O(nlgn),这是一个基础知识。 归并排序空间复杂度始终为 O(n),包括数组。 如果你把空间树画出来,看起来空间复杂度是O(nlgn)。然而,由于代码是深度优先代码,您将始终仅沿着树的一个分支进行扩展,因此,所需的总空间使用量始终受 O(3n) = O(n) 的限制。

2023 年 10 月 24 日更新:有一个问题是关于我如何得出 3n 上限的。 我在评论中的解释并重新粘贴在这里。 3n 的数学证明与为什么从未排序数组构建堆的时间复杂度上限为 2n 次交换的时间复杂度非常相似,这需要 O(2n) = O(n) 时间。在这种情况下,始终只有 1 个额外分支。因此,可以将其视为为 1 个附加分支再次执行 buildHeap。因此,它将受到另一个 n 的限制,总上限为 3n,即 O(3n) = O(n)。请注意,在本例中,我们使用 buildHeap(inputArray) 时间复杂度中的类似数学来证明单线程归并排序的空间复杂度,而不是时间复杂度。当我有时间的时候,我可以为此写出完整的严格的数学证明。

  • 构建堆的时间复杂度怎么可能是O(n)? https://stackoverflow.com/questions/9755721/how-can-building-a-heap-be-on-time-complexity

比如说,如果你把空间树画出来,看起来是O(nlgn)

                             16                                 | 16
                            /  \                              
                           /    \
                          /      \
                         /        \
                        8          8                            | 16
                       / \        / \
                      /   \      /   \
                     4     4    4     4                         | 16
                    / \   / \  / \   / \
                   2   2 2   2.....................             | 16
                  / \  /\ ........................
                 1  1  1 1 1 1 1 1 1 1 1 1 1 1 1 1              | 16

其中树的高度为 O(logn) => 空间复杂度为 O(nlogn + n) = O(nlogn)。 然而,实际代码并非如此,因为它不是并行执行的。例如,在 N = 16 的情况下,这就是归并排序代码的执行方式。 N = 16。

                           16
                          /
                         8
                        /
                       4
                     /
                    2
                   / \
                  1   1

注意使用的空间数量是 32 = 2n = 2*16

然后向上合并

                           16
                          /
                         8
                        /
                       4
                     /  \
                    2    2
                        / \                
                       1   1

即 34

                           16
                          /
                         8
                        / \
                       4   4
                          /
                         2
                        / \ 
                       1   1

36

然后向上合并

                           16
                          / \
                         8  8
                           / \
                          4   4
                             / \
                            2   2
                                /\
                               1  1

16 + 16 + 14 = 46

在更大的情况下,n = 64

                     64
                    /  \
                   32  32
                       / \
                      16  16
                          / \
                         8  8
                           / \
                          4   4
                             / \
                            2   2
                                /\
                               1  1

这是 643 n = 3*64

您可以通过一般情况的归纳来证明这一点。

因此,即使使用数组实现,只要在合并后清理已用空间并且不是并行而是顺序执行代码,空间复杂度始终受 O(3n) = O(n) 限制。

我的实现示例如下:

templace<class X> 
void mergesort(X a[], int n) // X is a type using templates
{
    if (n==1)
    {
        return;
    }
    int q, p;
    q = n/2;
    p = n/2;
    //if(n % 2 == 1) p++; // increment by 1
    if(n & 0x1) p++; // increment by 1
        // note: doing and operator is much faster in hardware than calculating the mod (%)
    X b[q];

    int i = 0;
    for (i = 0; i < q; i++)
    {
        b[i] = a[i];
    }
    mergesort(b, i);
    // do mergesort here to save space
    // http://stackoverflow.com/questions/10342890/merge-sort-time-and-space-complexity/28641693#28641693
    // After returning from previous mergesort only do you create the next array.
    X c[p];
    int k = 0;
    for (int j = q; j < n; j++)
    {
        c[k] = a[j];
        k++;
    }
    mergesort(c, k);
    int r, s, t;
    t = 0; r = 0; s = 0;
    while( (r!= q) && (s != p))
    {
        if (b[r] <= c[s])
        {
            a[t] = b[r];
            r++;
        }
        else
        {
            a[t] = c[s];
            s++;
        }
        t++;
    }
    if (r==q)
    {
        while(s!=p)
        {
            a[t] = c[s];
            s++;
            t++;
        }
    }
    else
    {
        while(r != q)
        {
            a[t] = b[r];
            r++;
            t++;
        }
    }
    return;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

归并排序时间和空间复杂度 的相关文章

  • 使用 A 星查找路径的启发式函数

    I am trying to find a optimal solution for the following problem 每个节点内表示的数字表示为 x y 一个节点的相邻节点总是有一个y值为 当前节点 y 值 1 更改的成本为 1
  • pytesseract 无法从图像中识别复杂的数学公式

    我在用pytesseractpython 中的模块 pytesseract从图像中识别文本 但它不适用于包含复杂数学公式 例如根 推导 积分数学问题或方程 的图像 代码2 py Import modules from PIL import
  • 滚动或滑动窗口迭代器?

    我需要一个可在序列 迭代器 生成器上迭代的滚动窗口 又名滑动窗口 默认的 Python 迭代可以被视为一种特殊情况 其中窗口长度为 1 我当前正在使用以下代码 我怎样才能更优雅和 或更有效地做到这一点 def rolling window
  • 如何高效生成总和在指定范围内的所有组合(在所有深度)

    假设您有一组值 1 1 1 12 12 16 如何生成总和在预定义范围内的所有可能组合 不重复 min max 例如 这里是 所有深度的 范围在13 and 17 1 12 1 1 12 1 1 1 12 16 1 16 这假设具有相同值的
  • 如何提高洪水填充例程的性能?

    我正在我的应用程序中实现四路洪水填充 伪代码如下 Flood fill node target color replacement color 1 If the color of node is not equal to target co
  • 字符串的渐进单词组合

    我需要获得字符串的渐进单词组合 例如 这是字符串 输出 这是字符串 这是 这个字符串 是字符串 这 是 细绳 你知道类似的算法吗 我需要php语言 谢谢 这是解决您问题的简单代码 我将每个字符串递归地连接到数组中的其余字符串 string
  • 分组符号最大长度平衡子序列

    将 B 视为分组符号 和 的序列 如果 B 的长度为 0 或 B 具有以下形式之一 则称 B 为平衡序列 X Y 或 X Y 或 X Y 其中 X 和 Y 本身是平衡的 平衡示例 现在的问题是找到一种有效的算法来找到给定输入的最大长度平衡子
  • Diamond-Square 算法的平滑问题

    我正在使用菱形方形算法来生成随机地形 它工作得很好 除了我让这些大圆锥形状要么伸出或伸入地形 问题似乎在于 时不时会有一个点被设置得太高或太低 Here is a picture of the problem And it can be b
  • 求一根棒可以切割的最大片数

    这是完整的问题陈述 给定一根长度为n的绳子 你需要找到最大的绳子数你可以让每一段的长度都在集合 a b c 中给定三个值a b c 我知道可以通过动态规划来实现最优解 但是 我还没有学过这个主题 我需要递归地解决这个问题 对于递归 主要的事
  • 对列表中的相邻元素进行分组

    假设我想编写一个函数来执行此操作 输入 1 1 3 3 4 2 2 5 6 6 输出 1 1 3 3 4 2 2 5 6 6 它将相同的相邻元素分组 这个方法的名称应该是什么 此操作有标准名称吗 In 1 1 3 3 4 2 2 5 6 6
  • 随机排列

    我无法找到一种随机洗牌元素的好方法std vector经过一些操作后 恢复原来的顺序 我知道这应该是一个相当简单的算法 但我想我太累了 由于我被迫使用自定义随机数生成器类 我想我不能使用std random shuffle 无论如何这没有帮
  • java中的Anagram算法

    我想做字谜算法但是 这段代码不起作用 我的错在哪里 例如 des 和 sed 是字谜 但输出不是字谜 同时我必须使用字符串方法 不是数组 public static boolean isAnagram String s1 String s2
  • 在大文件中查找重复项

    我有一个非常大的文件 大约有 1500 万个条目 文件中的每一行都包含一个字符串 称为键 我需要使用 java 查找文件中的重复条目 我尝试使用哈希图并检测重复的条目 显然 这种方法向我抛出了 java lang OutOfMemoryEr
  • 如何计算一组字符串的最短唯一前缀?

    这是一个非常常见的算法命令行解析 给定一组预定义的长选项名称 计算唯一标识这些选项之一的最短前缀 例如 对于以下选项 help hostname portnumber name polymorphic 这将是输出 he ho por n p
  • 如何在大空间尺度上加速A*算法?

    From http ccl northwestern edu netlogo models community Astardemo http ccl northwestern edu netlogo models community Ast
  • 让电脑实现360度=0度,旋转炮塔

    我正在制作一个游戏 其中有一个计算机控制的炮塔 炮塔可360度旋转 它使用 trig 找出枪瞄准所需的角度 obj deg 并将枪的当前角度存储在 gun deg 下面的代码以设定的速度旋转枪 if objdeg gt gundeg gun
  • 广度优先搜索:检查访问状态的时机

    在有向图的广度优先搜索中 可能循环 当一个节点出队时 其所有尚未访问的子节点都会入队 并且该过程将继续 直到队列为空 有一次 我以相反的方式实现它 将节点的所有子节点排队 并在节点出队时检查访问状态 如果正在出队的节点之前已被访问过 则该节
  • 插入排序 - 如何接受输入并打印排序后的数组

    我试图做一个插入排序程序 它接受任何数据类型 Int Double String 然后打印排序后的数组 我知道我的代码可以工作 但我无法找出真正的问题 import java util public class MyInsertionSor
  • Python 将字符串组合成尽可能短的字符串?

    如果我有一个字符串列表 我想将它们组合成一个具有重叠字符的字符串 如果没有剩余的重叠字符串 请将其添加到末尾 这是一个过于简化的版本 input one two output twone 我正在寻找一种方法来对输入列表中的任意数量的字符串执
  • 添加到 SortedSet 及其复杂性

    MSDN 声明如下SortedSet T Add 方法 http msdn microsoft com en us library dd411709 28VS 100 29 aspx 如果 Count 小于内部数组的容量 则此方法的操作时间

随机推荐