【问题标题】:correctness of fast small order statistic algorithm for odd-length array奇数数组快速小阶统计算法的正确性
【发布时间】:2018-05-29 04:25:40
【问题描述】:

Problem 9-3 of the textbook Intro to Algorithms (CLRS) 描述了一种快速 O(n) 算法,用于查找长度为 n 的数组的 k 阶统计量(排序时数组中的第 k 个元素),对于 k 远小于的特定情况n.当 n 为奇数时,我不确定这个算法的正确性,并希望找到一种方法来证明它是正确的。

基本思想是我们首先将数组分成两部分,第一部分包含 floor(n/2) 个元素,第二部分包含 ceil(n/2) 个元素。然后,我们将前半部分的每个元素与后半部分的相应元素“配对”。当 n 为奇数时,这会留下一个剩余的未配对元素。

对于每对合作伙伴,我们确保左侧合作伙伴 >= 右侧合作伙伴,如果不是,则交换两者。然后,递归地找到下半场的 k 阶统计量,将下半场进行的任何交换与上半场的相应交换镜像。之后,整个数组的k阶统计量要么在前半部分的前k个元素中,要么在后半部分的前k个元素中。

我的困惑来自数组长度 n 为奇数的情况,并且后半部分有一个单独的元素没有伙伴。由于递归是在后半部分执行的,由数组的最后一个 ceil(n/2) 元素组成,包括唯一的无伙伴最后一个元素,我们应该将下半部分进行的所有交换与相应的交换中的交换进行镜像上半场的合作伙伴,当其中一个交换涉及到最后的元素时,不清楚该怎么做,因为它没有合作伙伴。

教科书似乎并没有特别注意这个问题,所以我假设当交换涉及到最后一个元素时,那么在上半场根本不要做任何伙伴的镜像动作。结果,最后一个元素只是简单地“窃取”了与之交换的任何人的伙伴。但是,在这种情况下,是否有一种简单的方法可以查看算法是否仍然正确?如果当最后一个元素窃取了别人的伙伴时,伙伴实际上是第 k 阶统计量,然后被交换到一个无法访问的位置怎么办?涉及顺序统计选择的递归和分区机制对我来说非常不透明,因此我不能自信地排除这种情况。

【问题讨论】:

    标签: arrays algorithm sorting median median-of-medians


    【解决方案1】:

    我认为您对算法的描述并不完全准确(但是您链接到的解释还远不清楚)。据我了解,该算法对于奇数长度数组正确的原因如下:

    让我们先看几个偶数长度数组的例子,n=10 和 k=3(即我们正在寻找第三小的元素,即 2):

    a.  5 2 7 6 1 9 3 8 4 0  
    b.  5 1 7 6 2 9 3 8 4 0  
    c.  5 0 7 6 2 9 3 8 4 1  
    d.  5 0 7 6 2 9 3 8 1 4  
    

    如果我们将数组分成两部分,我们会得到:

    a.  5 2 7 6 1    9 3 8 4 0  
    b.  5 1 7 6 2    9 3 8 4 0  
    c.  5 0 7 6 2    9 3 8 4 1  
    d.  5 0 7 6 2    9 3 8 1 4  
    

    还有这些情侣:

    a.  (5,9) (2,3) (7,8) (6,4) (1,0)  <- 0 coupled with 1
    b.  (5,9) (1,3) (7,8) (6,4) (2,0)  <- 0 coupled with 2
    c.  (5,9) (0,3) (7,8) (6,4) (2,1)  <- 1 coupled with 2
    d.  (5,9) (0,3) (7,8) (6,1) (2,4)  <- 0, 1 and 2 not coupled with each other
    

    在比较和交换这对夫妇以使他们的最小元素在第一组之后,我们得到:

    a.  5 2 7 4 0    9 3 8 6 1  
    b.  5 1 7 4 0    9 3 8 6 2  
    c.  5 0 7 4 1    9 3 8 6 2  
    d.  5 0 7 1 2    9 3 8 6 4  
    

    你会看到最小的元素 0 总是在第一组。第二小的元素 1 要么在第一组,要么在第二组,如果它与最小的元素 0 耦合。第三小的元素 2 要么在第一组,要么在第二组,如果它与最小元素 0 或次小元素 1 相结合。

    所以最小的元素在第一组中,第二和第三小的元素可以在任一组中。这意味着第三小的元素要么是第一组中的 3 个最小元素之一,要么是第二组中的 2 (!) 个最小元素之一。

    a.  5 2 7 4 0    9 3 8 6 1  ->  0 2 4 + 1 3  
    b.  5 1 7 4 0    9 3 8 6 2  ->  0 1 4 + 2 3  
    c.  5 0 7 4 1    9 3 8 6 2  ->  0 1 4 + 2 3  
    d.  5 0 7 1 2    9 3 8 6 4  ->  0 1 2 + 3 4  
    

    因此,如果我们说整个数组的第 k 个最小元素现在是任一组中的第 k 个最小元素之一,那么第二组中就有一个可用的位置,这就是为什么,在一个奇数长度的数组,我们会将未耦合的元素添加到第二组。无论解耦元素是否是我们正在寻找的元素,它肯定是任一组中第 k 个最小的元素之一。

    实际上更正确的说法是,第 k 个最小的元素要么是第一组中的 k 个最小元素之一,要么是第二组中 k/2+1 个最小的元素之一。我实际上不确定该算法是最优的,甚至是正确的。有很多重复的比较和交换,当交换另一组中的对应元素时,跟踪一对夫妇并交换一组中的元素的想法似乎没有意义。

    【讨论】:

    • 将其减少到第二组中的 k/2+1 个最小元素似乎是关键,并且允许我们至少将未耦合的元素与这些元素放在一起,而无需首先将其包含在镜像中,并且我认为这是一个更好的方法。 (我直接从该书旧版的官方解决方案手册中获取了我的描述,似乎我原始帖子中的链接也引用了该链接。官方解决方案将较小的元素放在数组的右半边而不是左半边一半,这样当递归完成时,在右半部分,它包括未配对的元素)
    猜你喜欢
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2012-12-05
    • 1970-01-01
    • 2018-06-26
    • 2012-07-07
    相关资源
    最近更新 更多