Algorithm 了解中值选择算法?

Algorithm 了解中值选择算法?,algorithm,recursion,selection,data-partitioning,Algorithm,Recursion,Selection,Data Partitioning,我目前在业余时间学习算法,但在学习第3章选择算法时有以下问题 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

我目前在业余时间学习算法,但在学习第3章选择算法时有以下问题

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)
}
我知道,如果我使用的是从a到n的数组,我可以使用select算法找到中间数n/2的最小数

1但这是我一直在努力理解的一点。A=[3,7,5,1,4,2,6,2]。假设这是数组。在每次调用分区后数组的内容是什么,以及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
}

我正在使用的这本书叫安妮·卡尔德瓦伊的《算法的推导》。

这个算法分两步工作。分区步骤的工作方式是拾取一些枢轴元素,然后重新排列数组元素,使小于枢轴的所有元素都位于一侧,大于枢轴的所有元素都位于另一侧,并且枢轴位于正确的位置。例如,给定数组

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个最小的元素。然后,关于我们选择的轴,有三个选项:

枢轴位于位置k。然后,由于枢轴位于正确的位置,因此我们要查找的值必须是枢轴。我们结束了。 枢轴位于大于k的位置。那么第k个最小的元素必须在数组中枢轴之前的部分,所以我们可以递归地搜索数组中该部分的第k个最小元素。 枢轴位于小于k的位置。那么第k个最小元素必须在数组的上部区域的某个地方,我们可以在那里递归。 在我们的例子中,假设我们想要第二个最小的元素,即位置2处的元素。由于枢轴最终位于位置3,这意味着第二个最小的元素必须位于数组的前半部分的某个位置,因此我们将在子数组上递归

2  1

如果我们想要实际的中值元素,因为枢轴最终在数组的中间敲击,我们只输出中值为3并且完成。< /P> 最后,如果我们想要第四个最小的元素,那么由于枢轴位于位置4之前,我们将在数组的上半部分递归,即

5  4
在这里寻找第一个最小的元素,因为在这个区域之前有三个元素

算法的其余部分是关于如何执行分区步骤的详细信息,分区步骤可能是算法中最复杂的部分,以及如何执行关于是否递归的三向选择,难度要小一些。不过,希望这种高级结构能帮助算法变得更有意义


希望这有帮助

谢谢你,我刚刚读过,它比这本书更容易理解。不过,我还有一个问题,如果A是按相反顺序排序的,即A=[n,n-1,…,2,1],将进行多少个递归调用来选择?我将把这作为一个练习^ ^,但作为一个提示,请注意算法每次都选择数组的第一个元素作为轴心。这将在哪里移动枢轴?其余的元素将以什么顺序结束?同样作为一个提示,想想快速排序在这里可能做什么。第3点的第一句话,我想你的意思是枢轴在小于k的位置。你的第2点说枢轴小于k。接下来的句子说目标必须在枢轴之前。目标不应该在枢轴之后吗?3也有同样的问题,但正好相反。这就是为什么我只使用std::nth_元素并避免创建我自己的bug。