【问题标题】:Understanding a median selection algorithm?了解中值选择算法?
【发布时间】:2012-03-23 09:46:04
【问题描述】:

我目前在业余时间学习算法,但在学习第 3 章 select() 算法时有以下问题。

我知道如果我使用从 A 到 n 个数字的数组,我可以使用 select() 算法来查找中位数(第 n/2 个最小的数字)。

1) 但这是我难以理解的一点。 A = [3, 7, 5, 1, 4, 2, 6, 2]。假设这是数组。每次调用 Partition() 后数组的内容是什么,每次递归调用 Select() 的参数是什么。

有人可以解释一下他们是如何解决这个问题的吗?

以下是两种算法的伪代码。

Select(A, p, r, k) {
    /* return k-th smallest number in A[p..r] */
    if (p==r) return A[p] /* base case */
    q := Partition(A,p,r)
    len := q – p + 1
    if (k == len) return A[q]
    else if (k<len) return Select(A,p,q-1,k)
    else return Select(A,q+1,r,k-len)
}

第二个代码是

Partition(A, p, r) { /* partition A[p..r] */
    x := A[r] /* pivot */
    i := p-1
    for j := p to r-1 {
        if (A[j] <= x) {
            i++
            swap(A[i], A[j])
        }
    }
    swap(A[i+1], A[r])
    return i+1
}

我正在使用的这本书是 Anne Kaldewaij 的算法推导

【问题讨论】:

    标签: algorithm recursion selection data-partitioning


    【解决方案1】:

    此算法分两步工作。分区步骤通过选择一些枢轴元素,然后重新排列数组的元素,使得小于枢轴的所有元素都位于一侧,大于枢轴的所有元素都位于另一侧,并且枢轴位于正确的位置。例如,给定数组

    3  2  5  1  4
    

    如果我们选择一个 3 的枢轴,那么我们可以像这样对数组进行分区:

    2  1  3  5  4
    +--+  ^  +--+
     ^    |    ^
     |    |    +--- Elements greater than 3
     |    +-------- 3, in the right place
     +------------- Elements less than 3
    

    请注意,我们还没有对数组进行排序;我们刚刚使它更接近被排序。顺便说一下,这是快速排序的第一步。

    然后该算法使用以下逻辑。假设我们要按排序顺序找到属于索引 k 的元素(第 k 个最小的元素)。然后,关于我们选择的支点,有三个选项:

    1. 枢轴位于位置 k。然后,由于枢轴在正确的位置,我们正在寻找的值必须是枢轴。我们完成了。
    2. 枢轴位于大于 k 的位置。那么第 k 个最小的元素必须在数组中枢轴之前的部分中,因此我们可以递归地在数组的该部分中搜索第 k 个最小的元素。
    3. 枢轴位于小于 k 的位置。那么第 k 个最小的元素必须在数组的上部区域的某个地方,我们可以在那里递归。

    在我们的例子中,假设我们想要第二小的元素(位于位置 2 的元素)。由于枢轴在位置 3 结束,这意味着第二小的元素必须在数组的前半部分中的某个位置,因此我们将递归子数组

    2  1
    

    如果我们想要实际的中值元素,因为枢轴最终落在数组的中间,我们只需要输出中值是 3 就可以了。

    最后,如果我们想要第四小的元素,那么由于枢轴在位置 4 之前,我们将递归到数组的上半部分,即

    5  4
    

    并且会在这里寻找第一个最小的元素,因为在这个区域之前有三个元素。

    算法的其余部分是如何进行分区步骤的细节(这可能是算法中涉及最多的部分)以及如何进行是否递归的三向选择(难度稍小) )。不过,希望这种高级结构有助于算法更有意义。

    希望这会有所帮助!

    【讨论】:

    • 谢谢你,我刚读了它,它比书更容易理解。不过,我还有一个问题,如果 A 是反向排序的,即 A = [n, n-1, ..., 2, 1],将会对 Select() 进行多少次递归调用?
    • 我将把它作为练习 ^_^,但作为提示,请注意该算法每次都选择数组的第一个元素作为枢轴。这将把枢轴移到哪里?其余元素将以什么顺序结束?另外作为提示,请考虑一下快速排序在这里可能会做什么。
    • 第 3 点的第一句话,我认为您的意思是“枢轴在位置 小于 比 k”。
    • 您的第 2 点说“枢轴小于 k”。然后下面的句子说目标必须是 before 枢轴。目标不应该在 枢轴之后吗?与 #3 相同的问题,但相反。
    • 这就是为什么我只使用std::nth_element 并避免创建自己的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 2014-09-16
    • 2010-10-05
    • 2017-02-11
    • 2015-05-08
    相关资源
    最近更新 更多