shellsort排序有趣的試驗

趙年峰發表於2013-01-26

shellsort排序有趣的試驗

今天和同事討論關於一個shell排序的問題。

原因是在<演算法>這本書上看到的方法,其中程式碼就不貼出來了,因為效率不是十分高。那麼同事給我演示的是23秒多,資料量是100萬。我當時用python寫了半天也沒逾越這個數!我們機器是一樣的配置一樣的型號,幾乎沒有不同,除了密碼!處理器是i5 2450 4核心,使用的是同樣的資料樣本。我用的是python2.5,他使用的是python2.7。因為程式是在同一個機器上跑的,跑完到另一個機器跑。

wiki版本(不少網站都會貼著個程式碼)

def shellSort(array):
    "Shell sort using Shell's (original) gap sequence: n/2, n/4, ..., 1."
    gap = len(array) // 2
    # loop over the gaps
    while gap > 0:
    # do the insertion sort
        for i in range(gap, len(array)):
            val = array[i]
            j = i
            while j >= gap and array[j - gap] > val:
                array[j] = array[j - gap]
                j -= gap
            array[j] = val
        gap //= 2

然後我發現我程式碼的中間變數和冗餘程式碼十分多,我嘗試砍掉中間變數。我們就用中間修改差不多的原始版本吧,我們這裡做為第一版本!

def sort(a):
    n = len(a)
    h = n // 2
    while h > 0:
        #print h
        for i in xrange(h , n):
            val = a[i] #注意這個地方
            for j in xrange(i,h-2,-h):
                if a[j-h] > val : temp = a[j-h] ; a[j-h] = a[j] ; a[j] = temp
                else: break
        h //= 2

第1次修改

這個版本我修改掉了交換值,這個小小的增加一個開銷pack和unpack的時候,總體會增加不到0.01秒。但程式碼的可讀性很高!

def sort(a):
    n = len(a)
    h = n // 2
    while h > 0:
        #print h
        for i in xrange(h , n):
            val = a[i]
            for j in xrange(i,h-2,-h):
                if a[j-h] > val : a[j],a[j-h] = a[j-h],a[j]
                else: break
        h //= 2

第2次修改:

這裡很重要,我修改掉了else。這裡用了一個測試中看到的情況1就是如果子條件內進行for迴圈時,如果發現需要交換的變數,那麼迴圈可以結束!這個直接減少了大概10秒左右的開銷,也就是接近,有的時候會快過wiki版本的平均值。

def sort(a):
    n = len(a)
    h = n // 2
    while h > 0:
        #print h
        for i in xrange(h , n):
            val = a[i]
            for j in xrange(i,h-2,-h):
                if a[j-h] > val : a[j],a[j-h] = a[j-h],a[j] ; break
        h //= 2

最終版本:

這裡我去掉了臨時變數,這裡很關鍵,秒殺wiki版本的另一個重要 情況2:情況1 發生的前置條件中的被對比值必然是要交換的值。根據這個直接改掉程式,秒殺接近4個秒單位!

def sort(a):
    n = len(a)
    h = n // 2
    while h > 0:
        for i in xrange(h , n):    
            for j in xrange(i,h-2,-h):
                if a[j-h] > a[j] : a[j],a[j-h] = a[j-h],a[j] ; break
        h //= 2

這裡為什麼說是情況,而不是說定理?因為我證明不了。。哈哈。這個過程太複雜。 至此,算是7行解決了這個問題,從時間開銷和程式碼行數都完爆wiki版本的程式。

總結:感謝圖靈能夠出版<演算法>這本書的翻譯版本,更感謝@一盆花 謝大給我們帶來這麼好的書。只有思考才會發現,只有發現才能改變,改變錯了,再思考,呵呵。

相關文章