【问题标题】:Find K-th largest element with QuickSelect in Python在 Python 中使用 QuickSelect 查找第 K 个最大的元素
【发布时间】:2021-08-29 15:36:36
【问题描述】:

我是 Python 新手,正在练习编写代码,但遇到了一些麻烦。

我正在尝试实现 QuickSelect 以提取 K 最大元素

这是我的代码;

def partition(A, left, right): 
    pivot = random.randrange(left, right)  # pick a random number as pivot
    i = left - 1
    for j in range(left, right): 
        if A[j] <= pivot: 
            i = i+1 
            A[i], A[j] = A[j], A[i]
    A[i+1], A[right] = A[right], A[i+1] 
    return i+1

def QuickSelect(A, K, left, right): # Array, K-th element
    if left == right:
        return A[left]
    q = partition(A, left, right)
    i = q - left + 1
    if K == i:
        return A[i]
    if K < i:
        return QuickSelect(A, K, left, q - 1)
    else:
        return QuickSelect(A, K - i, q + 1, right)

尝试执行算法以获得第 5 高的元素:

a = get_random_array(10, 100)
print("array unsorted=" ,  a)
print("array sorted=", sorted(a))
print("result:" , QuickSelect(A = a, K = 5, left = 0, right = len(a)-1)) #I want the 5-th highest element

得到这个结果:

array unsorted = [71, 34, 0, 36, 26, 15, 3, 69, 93, 85]
array sorted = [0, 3, 15, 26, 34, 36, 69, 71, 85, 93]
result: 3

结果错误,因为 3 不是第 5 高的元素。

错误是在partition(A, left, right) 还是QuickSelect(A, K, left, right)? 你能帮我解决它吗?谢谢!

【问题讨论】:

  • 这段代码没有运行:你将i = 5作为参数传递给QuickSelect,但它没有这个命名参数。
  • @trincot 我通过传递K = 5 解决了i = 5 的问题,但仍然是同样的问题。函数中的索引是否有错误?

标签: python arrays algorithm quickselect


【解决方案1】:

您的代码中有几个问题。

  • 代码将pivot 视为一个,但它是一个索引
  • 在开始循环之前,应首先将枢轴移开(到right
  • K == i 时,您不应返回A[i],因为i相对,基于1 的索引。你应该return A[q]
  • 不是一个严重的问题,但randrange(left, right) 永远不会返回right,所以可能你想做randrange(left, right + 1)randint(left, right)

更正后的代码:

def partition(A, left, right): 
    # This gets an index, not a value:
    pivotindex = random.randint(left, right)  # allow right to be selected
    pivot = A[pivotindex]  # this is the pivot value
    # move the value out of the way
    A[right], A[pivotindex] = A[pivotindex], A[right]
    i = left - 1
    for j in range(left, right): 
        if A[j] < pivot:
            i += 1 
            A[i], A[j] = A[j], A[i]
    A[i+1], A[right] = A[right], A[i+1] 
    return i + 1

def QuickSelect(A, K, left, right):
    if left == right:
        return A[left]
    q = partition(A, left, right)
    i = q - left + 1
    if K == i:
        return A[q]  # this is the element you want to return
    if K < i:
        return QuickSelect(A, K, left, q - 1)
    else:
        return QuickSelect(A, K - i, q + 1, right)

【讨论】:

    【解决方案2】:

    您的两个功能都有问题。您正在将枢轴设置为分区函数

    random.randrange(left, right)
    

    改为将其设置为

    A[right] 
    
    def partition(A, left, right): 
        pivot = A[right]  # pick a random number as pivot
        i = left 
        for j in range(left, right): 
            if A[j] <= pivot: 
                A[i], A[j] = A[j], A[i]
                i = i+1 
        A[i], A[right] = A[right], A[i]
       
        return i
    

    在第二个函数中重新修改如下

    def Quickselect(A, left, right, k): 
    
        if (k > 0 and k <= right - left + 1):
      
            q = partition(A, left, right)
            if (q - left == k - 1):
                return A[q] 
            if (q - left > k - 1):
                return Quickselect(A, left, q - 1, k) 
            return Quickselect(A, q + 1, right,
                                k - q + left - 1)
    

    参考: https://www.geeksforgeeks.org/quickselect-algorithm/

    块引用

    【讨论】:

      猜你喜欢
      • 2021-08-29
      • 1970-01-01
      • 1970-01-01
      • 2014-07-21
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      • 1970-01-01
      相关资源
      最近更新 更多