簡體   English   中英

在python中獲取大小為N的未排序列表中獲取k個最小數字的最快方法?

[英]fastest method of getting k smallest numbers in unsorted list of size N in python?

使用python在大小為N的未排序列表中獲取k個最小數字的最快方法是什么?
對大數字列表進行排序是否更快,然后得到k個最小的數字,
或者通過查找列表中的最小值k次來獲得k個最小數字,確保在下次搜索之前從搜索中刪除找到的最小值?

您可以使用堆隊列; 它可以在O(NlogK)時間內從大小為N的列表中提供K個最大或最小的數字。

Python標准庫包含heapq模塊 ,其中包含一個heapq.nsmallest()函數

import heapq

k_smallest = heapq.nsmallest(k, input_list)

在內部,這會創建一個大小為K的堆,其中包含輸入列表的前K個元素,然后迭代剩余的NK元素,將每個元素推送到堆中,然后彈出最大的元素。 這樣的推送和彈出需要記錄K時間,使得整個操作O(NlogK)。

該函數還優化了以下邊緣情況:

  • 如果K為1,則使用min()函數,給出O(N)結果。
  • 如果K> = N,則函數使用排序,因為在這種情況下O(NlogN)將擊敗O(NlogK)。

更好的選擇是使用introselect算法 ,它提供O(n)選項。 我所知道的唯一實現是使用numpy.partition()函數

import numpy

# assuming you have a python list, you need to convert to a numpy array first
array = numpy.array(input_list)
# partition, slice back to the k smallest elements, convert back to a Python list
k_smallest = numpy.partition(array, k)[:k].tolist()

除了需要安裝numpy ,這還需要N個內存(與heapq相比為K),因為為分區創建了列表的副本。

如果您只想要索引,則可以使用以下任一變量:

heapq.nsmallest(k, range(len(input_list)), key=input_list.__getitem__)  # O(NlogK)
numpy.argpartition(numpy.array(input_list), k)[:k].tolist()  # O(N)

編輯:這假定列表是不可變的。 如果列表是一個數組並且可以修改,則可以使用線性方法。

通過使用大小為k + 1的堆,可以將復雜度降低到O(n * log k)

  1. 最初將前k元素放入min-heap中。
  2. 對於每個后續元素,將元素添加為葉子並堆積。
  3. 用下一個元素替換最后一個元素。

Heapify可以在對數時間內完成,因此時間復雜度如上所述。

您可以使用選擇算法O(kn)執行此操作。 一旦kn >= n log n ,切換到排序。 也就是說,選擇算法的常數往往比快速排序上的常數高很多,所以你真的需要比較i (kn)j (n log n) 在實踐中,除非你處理大的n或非常小的k,否則通常更希望排序。

編輯:查看評論。 它實際上好多了

你可能想看看heapq

In [109]: L = [random.randint(1,1000) for _ in range(100)]

In [110]: heapq.nsmallest(10, L)
Out[110]: [1, 17, 17, 19, 24, 37, 37, 45, 63, 73]

如果不需要對第k個最小數字的列表進行排序,則可以使用像introselect這樣的選擇算法在O(n)時間內完成 標准庫沒有附帶,但NumPy有numpy.partition用於工作:

partitioned = numpy.partition(l, k)
# The subarray partitioned[:k] now contains the k smallest elements.

在heapq中使用nsmallest數字的代碼較少,但如果您希望自己實現它,這是一種簡單的方法。 這個解決方案只需要循環數據一次,但是由於他應用並且在O(log n)上運行,因此該算法在較小數量的k上表現最佳。

import heapq

def getsmallest(arr, k):
    m = [-x for x in l[:k]]
    heapq.heapify(m)
    for num in arr[5:]:
        print num, m
        heapq.heappush(m, max(-num, heapq.heappop(m)))
    return m

if __name__ == '__main__':
    l = [1,2,3,52,2,3,1]
    print getsmallest(l, 5)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM