Algorithm 将数组的元素分成3组
我必须把数组的元素分成3组。这需要在不排序数组的情况下完成。考虑例子 我们有120个未排序的值,因此最小的40个值需要在第一组中,接下来的40个值需要在第二组中,最大的40个值需要在第三组中 我在考虑中值中值法,但无法将其应用于我的问题,请建议一种算法。您可以在阵列上调用两次,以便在适当的位置和平均情况下以线性时间执行此操作。通过使用线性时间为quickselect选择最佳枢轴,最坏情况下的运行时也可以改进为O(n) 对于quickselect的两个调用,使用k=n/3。第一次调用时,在整个阵列上使用quickselect,第二次调用时,从arr[k..n-1](对于0索引阵列)使用quickselect 维基百科对quickselect的解释:Algorithm 将数组的元素分成3组,algorithm,computer-science,median-of-medians,Algorithm,Computer Science,Median Of Medians,我必须把数组的元素分成3组。这需要在不排序数组的情况下完成。考虑例子 我们有120个未排序的值,因此最小的40个值需要在第一组中,接下来的40个值需要在第二组中,最大的40个值需要在第三组中 我在考虑中值中值法,但无法将其应用于我的问题,请建议一种算法。您可以在阵列上调用两次,以便在适当的位置和平均情况下以线性时间执行此操作。通过使用线性时间为quickselect选择最佳枢轴,最坏情况下的运行时也可以改进为O(n) 对于quickselect的两个调用,使用k=n/3。第一次调用时,在整个阵列
k = n / 3
# First group smallest elements in array
quickselect(L, 0, n - 1, k) # Call quickselect on your entire array
# Then group middle elements in array
quickselect(L, k, n - 1, k) # Call quickselect on subarray
# Largest elements in array are already grouped so
# there is no need to call quickselect again
Quickselect使用与快速排序相同的总体方法,即选择一种
元素作为轴心,并基于
枢轴,因此小于或大于枢轴。然而,
quickselect不是像在快速排序中那样递归到两边,而是
只会递归到一个面–元素所在的面
寻找。这降低了O(n logn)(in)的平均复杂度
快速排序)到O(n)(在快速选择中)
与快速排序一样,quickselect通常作为就地
算法,并且除了选择第k个元素之外,它还部分
对数据进行排序。请参阅,以了解有关
与分拣的联系
要将数组元素分为3组,请使用以下用Python编写的算法并结合quickselect:
k = n / 3
# First group smallest elements in array
quickselect(L, 0, n - 1, k) # Call quickselect on your entire array
# Then group middle elements in array
quickselect(L, k, n - 1, k) # Call quickselect on subarray
# Largest elements in array are already grouped so
# there is no need to call quickselect again
所有这些的关键点是quickselect使用一个名为partition的子例程。分区将数组分为两部分,一部分大于给定元素,另一部分小于给定元素。因此,它将围绕该元素对数组进行部分排序,并返回其新的排序位置。因此,通过使用quickselect,可以在适当的位置和平均线性时间内,围绕第k个元素对数组进行部分排序(请注意,这与实际对整个数组进行排序不同)
quickselect的时间复杂性:
k = n / 3
# First group smallest elements in array
quickselect(L, 0, n - 1, k) # Call quickselect on your entire array
# Then group middle elements in array
quickselect(L, k, n - 1, k) # Call quickselect on subarray
# Largest elements in array are already grouped so
# there is no need to call quickselect again
from random import randint
def partition(L, left, right, pivotIndex):
'''partition L so it's ordered around L[pivotIndex]
also return its new sorted position in array'''
pivotValue = L[pivotIndex]
L[pivotIndex], L[right] = L[right], L[pivotIndex]
storeIndex = left
for i in xrange(left, right):
if L[i] < pivotValue:
L[storeIndex], L[i] = L[i], L[storeIndex]
storeIndex = storeIndex + 1
L[right], L[storeIndex] = L[storeIndex], L[right]
return storeIndex
def quickselect(L, left, right, k):
'''retrieve kth smallest element of L[left..right] inclusive
additionally partition L so that it's ordered around kth
smallest element'''
if left == right:
return L[left]
# Randomly choose pivot and partition around it
pivotIndex = randint(left, right)
pivotNewIndex = partition(L, left, right, pivotIndex)
pivotDist = pivotNewIndex - left + 1
if pivotDist == k:
return L[pivotNewIndex]
elif k < pivotDist:
return quickselect(L, left, pivotNewIndex - 1, k)
else:
return quickselect(L, pivotNewIndex + 1, right, k - pivotDist)
def main():
# Setup array of 120 elements [120..1]
n = 120
L = range(n, 0, -1)
k = n / 3
# First group smallest elements in array
quickselect(L, 0, n - 1, k) # Call quickselect on your entire array
# Then group middle elements in array
quickselect(L, k, n - 1, k) # Call quickselect on subarray
# Largest elements in array are already grouped so
# there is no need to call quickselect again
print L[:k], '\n'
print L[k:k*2], '\n'
print L[k*2:]
if __name__ == '__main__':
main()
来自随机导入randint
def分区(左、左、右、数据透视索引):
''分区L,所以它是围绕L[数据透视索引]排序的
还返回其在数组“”中的新排序位置
pivotValue=L[数据透视索引]
L[pivotIndex],L[right]=L[right],L[pivotIndex]
storeIndex=左
对于X范围内的i(左、右):
如果L[i]
我想看看。统计样本的第k阶统计量等于其第k个最小值。计算列表中第k个最小(或最大)元素的问题称为选择问题,由一个简单的方法解决
中位数的中间值是正确的。但是,您可能希望从数组中查找最小的第20个和第40个元素,而不是查找中值。就像找到中值一样,使用选择算法只需线性时间就可以找到两者。最后,遍历数组并根据这两个元素对元素进行分区,这也是线性时间
注:如果这是您在算法类中的练习,可能会帮助您:)分配一个与输入数组大小相同的数组 扫描输入数组一次,并跟踪数组的最小值和最大值。 同时将第二个数组的所有值设置为1。 计算
delta=(最大-最小)/3
。
再次扫描阵列,如果数字为>min+d,则将第二个阵列设置为2