![](/img/trans.png)
[英]Python algorithm to find the indexes of the k smallest number in an unsorted array?
[英]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)。
該函數還優化了以下邊緣情況:
min()
函數,給出O(N)結果。 更好的選擇是使用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)
。
k
元素放入min-heap中。 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.