Swift 合并排序算法的效率

Swift 合并排序算法的效率,swift,algorithm,sorting,mergesort,Swift,Algorithm,Sorting,Mergesort,我目前正在学习一门在线算法课程,在这门课程中,老师没有给出解决算法的代码,而是给出粗略的伪代码。因此,在上网寻找答案之前,我决定亲自尝试一下 在本例中,我们正在研究的算法是合并排序算法。在得到伪代码后,我们还针对数组中的n个项目分析了运行时算法。在快速分析之后,教师得出6nlog(base2)(n)+6n作为算法的近似运行时间 给出的伪代码仅用于算法的合并部分,如下所示: C = output [length = n] A = 1st sorted array [n/2] B = 2nd so

我目前正在学习一门在线算法课程,在这门课程中,老师没有给出解决算法的代码,而是给出粗略的伪代码。因此,在上网寻找答案之前,我决定亲自尝试一下

在本例中,我们正在研究的算法是合并排序算法。在得到伪代码后,我们还针对数组中的n个项目分析了运行时算法。在快速分析之后,教师得出
6nlog(base2)(n)+6n
作为算法的近似运行时间

给出的伪代码仅用于算法的合并部分,如下所示:

C = output [length = n]
A = 1st sorted array [n/2] 
B = 2nd sorted array [n/2] 
i = 1
j = 1
for k = 1 to n
    if A(i) < B(j)
        C(k) = A(i)
        i++
    else [B(j) < A(i)]
        C(k) = B(j) 
        j++
    end
end 
我的问题如下:

C = output [length = n]
A = 1st sorted array [n/2] 
B = 2nd sorted array [n/2] 
i = 1
j = 1
for k = 1 to n
    if A(i) < B(j)
        C(k) = A(i)
        i++
    else [B(j) < A(i)]
        C(k) = B(j) 
        j++
    end
end 
  • merge
    函数开头的
    guard
    语句是否真的会使其效率更低?考虑到我们总是将数组减半,它唯一适用于基本情况和数组中有奇数项的情况。
    在我看来,这实际上会增加更多的处理,并提供最小的回报,因为它发生的时间是当我们将数组减半到没有项目的时候

  • 关于合并中的
    if
    语句。因为它检查不止一个条件,这会影响我所写的算法的整体效率吗?如果是这样的话,对我来说,效果似乎会根据它何时会脱离
    If
    语句而有所不同(例如在第一个条件或第二个条件下)。
    在分析算法时,这是一个重要的问题吗?如果是的话,当它从算法中爆发出来时,你如何解释方差


  • 如果您能就我所写的内容向我提供任何其他分析/提示,我们将不胜感激。

    您很快就会了解到Big-O和Big-Theta,其中您不关心精确的运行时(请相信我的话,就像在一两次讲座中一样)。在此之前,您需要知道:

  • 是的,防护需要一些时间,但每次迭代的时间都是一样的。因此,如果每次迭代需要
    X
    时间,而没有保护,并且您执行
    n
    函数调用,那么它总共需要
    X*n
    时间。现在加入在每次通话中占用
    Y
    时间的Guar。现在您总共需要
    (X+Y)*n
    时间。这是一个常数因子,当
    n
    变得非常大时,与
    n
    因子相比,
    (X+Y)
    因子变得可以忽略不计。也就是说,如果您可以将函数
    X*n
    减少到
    (X+Y)*(logn)
    ,那么添加
    Y
    工作量是值得的,因为总的迭代次数较少

  • 同样的道理也适用于你的第二个问题。是的,检查“如果X或Y”比检查“如果X”需要更多的时间,但这是一个常数。额外时间不随
    n
    的大小而变化

    在某些语言中,只有在第一个条件失败时才检查第二个条件。我们如何解释这一点?最简单的解决方案是实现比较次数的上限为3次,而迭代次数可能会达到数百万次,且
    n
    。但是3是一个常量,所以每次迭代最多只能增加一个常量工作量。你可以深入到细节中,试着对第一、第二和第三个条件的分布情况进行推理,但通常你并不想走这条路。假装你总是做所有的比较


  • 因此,是的,如果您执行与以前相同的迭代次数,那么添加防护可能对您的运行时有害。但有时在每次迭代中添加额外的工作可以减少所需的迭代次数。

    非常感谢您帮助我们更好地理解这一点。事实上,我们确实学习了大O和大θ。压制这些常数让人感到尴尬,因为这几乎让守卫们感到“有道理”,即使他们不提供帮助。同时,编写高效算法的真正魔力在于真正能够去除绒毛,并以最有效的方式完成任务。在这种情况下,你能给我一个关于守卫是否合理的意见吗?从我的想法来看,对于n=偶数,它们不是,但是对于n=奇数,它们将我们带到n-1(虽然仍然是一个常数,但被抑制),警卫增加了处理时间,对吗。它们被放在那里的原因是为了可读性。警卫检查基本情况,在开始时这样做是一个好主意,这样你就不会忘记。同时,不同层次的优化将使它成为可能,这样在一般情况下,卫兵不会花费太多时间(如果他们是真的)。如果不需要,甚至不调用该函数会更好,在调用站点添加防护。它归结为可读性以及在您选择的语言中函数调用的代价有多高。就我个人而言,我总是喜欢在函数开始时检查基本情况。我想知道for循环中的6n部分是否认为a[I]或B[j]在合并期间被读取两次,一次在if期间,另一次在移动期间。