找到n元素集的第k个分位数。 (来自cormen)

时间:2010-10-11 14:49:29

标签: algorithm

n元素集的第k个分位数是k-1阶统计量,其将有序集划分为k个相等大小的集(在1内)。给出O(n lg k)时间算法以列出集合的第k个分位数。

直接的解决方案是选择每个k,2k,3k .. ik最小元素,其运行时间为O(kn)(k调用选择O(n)的过程)。但这可以优化,比O(kn)更好。在select过程中找到索引'i'的中位数中位数后,我们进行以下递归调用。

如果中位数i的中位数指数> k,递归调用选择左子阵列A [0 ... i]

中的第k个最小元素

如果i是< k,递归地选择右子阵列A [i + 1 ... n]中的第n-i + k个最小元素。

上面的递归调用可以修改如下,这会将因子'k'减少到'log k'吗?

如果中位数i的中位数指数> k,递归地选择左子阵列A [0 ... i]中的第k个最小元素,并递归地选择右子阵列A [i + 1 ... n]中的第n个最小元素。

如果i是< k,递归地选择右子阵列A [i + 1 ... n]中的第n-i + k个最小元素,并递归地选择左子阵列A [0 ... i]中的第k个最小元素。

主要调用只是选择(A,k,n)。

4 个答案:

答案 0 :(得分:5)

请注意,我们使用修改后的PARTITION作为其最后一个输入参数的枢轴索引。

您从KTH-QUANTILES(A, 1, n, 1, k-1, k)

开始
KTH-QUANTILES(A, p, r, i, j, k)
n=A.length
m=floor((i+j)/2)
q=floor(m(n/k))
q=q-p+1
q=SELECT(A, p, r, q)
q=PARTITION(A, p, r, q)
if i<m
    L=KTH-QUANTILES(A, p, q-1, i, m-1, k)
if m<j
    R=KTH-QUANTILES(A, q+1, r, m+1, j, k)
return L U A[q] U R

递归树的深度为lg k,因为分区是围绕给定顺序统计的中位数(从i到j)完成的。

在递归树的每个级别上都有Θ(n)个运算,因此运行时间为Θ(nlgk)。

答案 1 :(得分:2)

我没有通过你的方法,但这是来自Int的问题。 Cormen的算法。无论如何我自己都在寻找解决方案,我很乐意分享我的算法版本。试着反驳它的正确性:

我假设我们有一个O(n)统计发现算法。所以我可以在O(n)时间内找到第k个统计量。假设我说我将使用分而治之的方法找到所有n / k第k个分位数,以便:

如果我有n个元素,我将数组分成n'/ 2个部分,报告n'/ 2个分区的第k个分位数边界。并递归地报告剩余的分位数。本质上我正在做的是,在使用中值进行分区后,我将从左侧数组中提取最右侧的分位数,从右侧分区中提取最左侧的分位数,并在修剪这些数组后递归地运行算法。我的复杂性分析结果如下:

T(n,k)= 2 * T(n / 2,k / 2)+ O(n)。

事实证明这是O(nlogk),因为k / 2部分会更快地收敛,尽管你可能想要更严格地解决这个问题。我们也使用了n> k(从问题中可以看出。请注意,提取2个分位数并修整数组的任务将在O(n)中完成

答案 2 :(得分:0)

在不失一般性的前提下,假设n和k为2的幂。

我们首先使用SELECT在时间O(n)中找到n / 2阶统计量,然后将问题缩小为找到较小n / 2个元素的第k / 2个分位数和较大n个元素的k / 2个分位数/ 2个元素。

让T(n)表示算法在大小为n的输入上运行所花费的时间。
然后对于某个常数c,T(n)= cn + 2T(n / 2),基本情况为T(n / k)= O(1)。

然后我们有:T(n)≤cn + 2T(n / 2)≤2cn + 4T(n / 4)≤3cn + 8T(n / 8)。 。 。 ≤log(k)cn + kT(n / k)≤log(k)cn + O(k)= O(nlogk)。

cc。解决方案手册

答案 3 :(得分:0)

“”“ 第k分位数 “”“

随机导入数学

将SelectDetermin_1导入为SD

Q = []

def kQuantiles(A,l,r,k):#O(nlgk)

global Q
if k == 1:
    return
i = math.floor(k/2)
n = r-l+1
incr = math.floor(i*n/k)
p = SD.Dselect(A,l,r,l+incr,5)
Q.append((l+incr,p))
q = SD.partition(A,l,r,l+incr)
kQuantiles(A,l,q,math.floor(k/2))
kQuantiles(A,q,r,math.ceil(k/2))

k = 13

A = list(range(100))

random.shuffle(A)

kQuantiles(A,0,len(A)-1,k)

Q.sort()#O(klgk)

print([x表示_,x in x])

def BFkQuantile(A,k):#O(kn)

out = []
Q = [math.floor(i * len(A)/k + 1/2) for i in range(1,k)]
for stat in Q:
    out.append(SD.Dselect(A,0,len(A)-1,stat,5))
return out

print(BFkQuantile(A,k))

Dselect和partition的位置与Avi Cohen的帖子中的相同,将A中的条目返回到所需索引以及列表进行分区的索引。

我无法使之前的代码正常工作,所以我想检查一下是否可以