抽象到位合并排序以进行有效的合并排序

时间:2013-08-20 05:46:59

标签: algorithm sorting mergesort

我正在阅读Robert Sedgewick关于C ++算法中的合并排序,并有以下问题。

static void mergeAB(ITEM[] c, int cl, ITEM[] a, int al, int ar, ITEM[] b, int bl, int br )
{ 
    int i = al, j = bl;
    for (int k = cl; k < cl+ar-al+br-bl+1; k++)
    {
        if (i > ar) { c[k] = b[j++]; continue; }
        if (j > br) { c[k] = a[i++]; continue; }
        c[k] = less(a[i], b[j]) ? a[i++] : b[j++];
    }
}
  

基本合并的特征值得注意的是   内循环包括两个测试,以确定是否结束   已达到两个输入数组。当然,通常这两个测试   失败,因此情况因使用哨兵钥匙而大声呼喊   允许删除测试。也就是说,如果元素具有键值   大于所有其他键的键被添加到a的末尾   和aux数组一样,测试可以删除,因为当a(b)数组时   耗尽,哨兵导致c数组的下一个元素   取自b(a)数组,直到合并完成。

     

然而,使用哨兵并不总是那么容易,因为它   可能不容易知道最大的键值或因为空间可能   不方便。

     

对于合并,有一个简单的补救措施。该方法基于   以下想法:鉴于我们已经辞职将数组复制到   实现就地抽象,我们只需将第二个数组放入   复制时的逆序(无需额外费用),以便它   相关索引从右向左移动。这种安排导致   最大的元素 - 无论是哪个数组 - 作为哨兵   另一个阵列。

我对上述文字的疑问

  1. 当a(b)数组耗尽时语句是什么?什么是“a(b)”?

  2. 为什么作者提到确定最大密钥并不容易确定最大密钥的空间?

  3. 作者的意思是“鉴于我们已经辞职复制数组”?什么是在这种情况下辞职?

  4. 请求用简单的例子来理解提到的简单补救措施?

2 个答案:

答案 0 :(得分:3)

  1. “当a(b)阵列耗尽时”是“当a阵列或b阵列耗尽时的简写”。

  2. 接口正在处理更大数组的子数组,所以你不能简单地写出数组的末尾。

  3. 代码将数据从两个数组复制到另一个数组中。由于这个副本是不可避免的,我们'不得不复制数组'意味着我们不情愿地接受必须复制数组是不可避免的。

  4. 整蛊......这需要一些时间才能弄明白是什么意思。

  5. Tangentially :这可能不是我编写循环的方式。我倾向于使用:

    int i = al, j = bl;
    for (int k = cl; i <= ar && j <= br; k++)
    {
        if (a[i] < b[j])
            c[k] = a[i++];
        else
            c[k] = b[j++];
    }
    while (i <= ar)
        c[k++] = a[i++];
    while (j <= br)
        c[k++] = b[j++];
    

    两个尾随循环中的一个没有做任何事情。修订后的主合并循环每次迭代有3次测试,而对于一次原始算法,每次迭代有4次测试。我没有正式测量它,但更简单的合并循环可能比原始的单循环算法更快。

    前三个问题几乎最适合English Language Learners

答案 1 :(得分:1)

a(b)和b(a)

有时,括号用于一次告诉一个或多个相似的短语:

  
    
      

当a(b)用尽时,我们从b(a)

复制元素     
  

表示:

  
    
      

当a耗尽时,我们从b复制元素,       当b用尽时,我们从

复制元素     
  

哨兵有什么困难

关于哨兵的两件令人讨厌的事情是

  1. 有时您的数组数据可能包含所有可能的值,因此没有值可以用作保证比数组中所有值更大的sentinel
  2. 使用sentinel而不是检查索引,看看你是否完成了一个数组,要求你有足够的空间在数组中存储一个额外的空间来存储sentinel
  3. 辞职

    我们程序员永远不会乐意复制(或移动)周围的东西,如果可能的话,将它们留在已经存在的地方(因为我们很懒)。 在这个版本的合并排序中,我们已经放弃了尝试不复制的东西...我们辞职。 鉴于我们必须复制,如果我们愿意,我们可以以相反的顺序复制事物(当然,以相反的顺序使用副本),因为这是免费的(*)。

    (*)在这个抽象级别是免费的,某些真实CPU的成本可能很高。几乎总是在表演区YMMV