簡體   English   中英

Python快速排序 - 列表理解與遞歸(分區例程)

[英]Python quicksort - List comprehension vs Recursion (partition routine)

我看了三個美麗的Quicksorts談話,並且正在忙着趕快行動。 我在python中的實現與c非常相似(選擇pivot,圍繞它進行分區並在越來越大的分區上遞歸)。 我認為這不是pythonic

所以這是在python中使用list comprehension的實現。

def qsort(list):
    if list == []: 
        return []
    pivot = list[0]
    l = qsort([x for x in list[1:] if x < pivot])
    u = qsort([x for x in list[1:] if x >= pivot])
    return l + [pivot] + u

讓我們調用遞歸方法qoortR。 現在我注意到qsortR比大型(r)列表的qsort運行慢得多。 實際上“cmp中超出了最大遞歸深度”,即使對於遞歸方法也是1000個elems。 我在sys.setrecursionlimit中重置。

一些數字:

list-compr 1000 elems 0.491770029068
recursion 1000 elems 2.24620914459
list-compr 2000 elems 0.992327928543
recursion 2000 elems 7.72630095482

所有代碼都在這里

我有一些問題:

  • 為什么列表理解這么快?
  • 對python中遞歸限制的一些啟示。 我首先將它設置為100000,在什么情況下我應該小心?
    • ('優化尾遞歸'究竟是什么意思,它是如何完成的?)
  • 試圖對我的筆記本電腦的1000000個元素進行排序(使用遞歸方法)。 如果我想要排序這么多元素,我該怎么辦? 什么樣的優化是可能的?
  1. 為什么列表理解這么快?

    因為名單理解暗示的C循環比使用Python的慢一般方法快得多for塊。

  2. 對python中遞歸限制的一些啟示。 我首先將它設置為100000,在什么情況下我應該小心?

    如果你的內存不足。

  3. 試圖對我的筆記本電腦的1000000個元素進行排序(使用遞歸方法)。 如果我想要排序這么多元素,我該怎么辦? 什么樣的優化是可能的?

    Python的遞歸會產生這樣的開銷,因為每次調用都會在每次調用時分配大量的堆棧內存空間。

    通常,迭代是答案(在統計上99%的用例中將提供更好的性能)。

    談論內存結構,如果你有簡單的數據結構,比如字符,整數,浮點數:使用內置的array.array ,它比list具有更高的內存效率。

您是否嘗試過編寫非遞歸的partition實現? 我懷疑性能差異純粹是partition實現。 您正在為實現中的每個元素進行遞歸。

更新

這是一個快速實現。 它仍然不是超快速甚至是高效的,但它比原來的遞歸更好。

>>> def partition(data):
...  pivot = data[0]
...  less, equal, greater = [], [], []
...  for elm in data:
...   if elm < pivot:
...    less.append(elm)
...   elif elm > pivot:
...    greater.append(elm)
...   else:
...    equal.append(elm)
...  return less, equal, greater
...
>>> def qsort2(data):
...  if data:
...   less, equal, greater = partition(data)
...   return qsort2(less) + equal + qsort2(greater)
...  return data
... 

我還認為“傳統”版本中生成的臨時列表數量較多。

當內存變得非常大時,嘗試將列表理解與就地算法進行比較。 下面的代碼在排序100K整數時會得到一個接近執行的時間,但在排序1M整數時,你可能會陷入列表推導解決方案。 我使用4Gb機器進行了測試。 完整代碼: http//snipt.org/Aaaje2

class QSort:
def __init__(self, lst):
    self.lst = lst

def sorted(self):
    self.qsort_swap(0, len(self.lst))
    return self.lst

def qsort_swap(self, begin, end):
    if (end - begin) > 1:
       pivot = self.lst[begin]
       l = begin + 1
       r = end
       while l < r:
           if self.lst[l] <= pivot:
               l += 1
           else:
               r -= 1
               self.lst[l], self.lst[r] = self.lst[r], self.lst[l]

       l -= 1
       self.lst[begin], self.lst[l] = self.lst[l], self.lst[begin]    
       # print begin, end, self.lst
       self.qsort_swap(begin, l)
       self.qsort_swap(r, end)     

暫無
暫無

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

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