Python線性時間排序——桶排序、基數排序與計數排序


1. 桶排序

1.1 范圍為1-M的桶排序

如果有一個數組A,包含N個整數,值從1到M,我們可以得到一種非常快速的排序,桶排序(bucket sort)。留置一個數組S,里面含有M個桶,初始化為0。然后遍歷數組A,讀入Ai時,S[Ai]增一。所有輸入被讀進后,掃描數組S得出排好序的表。該算法時間花費O(M+N),空間上不能原地排序。

初始化序列S

遍歷A修改序列S的項

舉個例子,排序一個數組[5,3,6,1,2,7,5,10]

值都在1-10之間,建立10個桶:

[0 0 0 0 0 0 0 0 0 0]    桶

[1 2 3 4 5 6 7 8 9 10]   桶代表的值

遍歷數組,第一個數字5,第五個桶加1

[0 0 0 0 1 0 0 0 0 0]

第二個數字3,第三個桶加1

[0 0 1 0 1 0 0 0 0 0]

遍歷后

[1 1 1 0 2 1 1 0 0 1]

輸出

[1 2 3 5 5 6 7 10]

代碼

import random
class bucketSort(object):
    def _max(self,oldlist):
        _max=oldlist[0]
        for i in oldlist:
            if i>_max:
                _max=i
        return _max
    def _min(self,oldlist):
        _min=oldlist[0]
        for i in oldlist:
            if i<_min:
                _min=i
        return _min
    def sort(self,oldlist):
        _max=self._max(oldlist)
        _min=self._min(oldlist)
        s=[0 for i in xrange(_min,_max+1)]
        for i in oldlist:
            s[i-_min]+=1
        current=_min
        n=0
        for i in s:
            while i>0:
                oldlist[n]=current
                i-=1
                n+=1
            current+=1
    def __call__(self,oldlist):
        self.sort(oldlist)
        return oldlist
if __name__=='__main__':
    a=[random.randint(0,100) for i in xrange(10)]
    bucketSort()(a)
    print a

1.2 區間[0,1)均勻分布的桶排序

當輸入符合均勻分布時,例如,元素均勻的分布在區間[0,1)上,可以將桶排序與其它排序方法結合使用。

如果序列的大小為n,就將[0,1)划分成n個相同大小的子區間(桶),然后將n個輸入數分布到各個桶中。先對各個桶中的數進行排序,然后按照次序把各桶中的元素列出來即可。

《算法導論》的描述圖:

代碼:

class bucketSort(object):
    def insertSort(self,a):
        n=len(a)
        if n<=1:
            pass
        for i in range(1,n):
            key=a[i]
            j=i-1
            while key<a[j] and j>=0:
                a[j+1]=a[j]
                j-=1
            a[j+1]=key
    def sort(self,a):
        n=len(a)
        s=[[] for i in xrange(n)]
        for i in a:
            s[int(i*n)].append(i)
        for i in s:
            self.insertSort(i)
        return [i for j in s for i in j]
    def __call__(self,a):
        return self.sort(a)
                      
if __name__=='__main__':
    from random import random
    from timeit import Timer
    a=[random() for i in xrange(10000)]
    def test_bucket_sort():
        bucketSort()(a)
    def test_builtin_sort():
        sorted(a)
    tests=[test_bucket_sort,test_builtin_sort]
    for test in tests:        
        name=test.__name__
        t=Timer(name+'()','from __main__ import '+name)
        print t.timeit(1)

2. 基數排序

基數排序一般用於長度相同的元素組成的數組。首先按照最低有效數字進行排序,然后由低位向高位進行。

329                720                720                329

457                355                329                355

657                436                436                436

839====≯ 457====≯ 839====≯ 457

436                657                355                657

720                329                457                720

355                839                657                839

基數排序可以看做是進行多趟桶排序。每個有效數字都在0-9之間,很適合桶排序,建10個桶很方便。

排序數組 64,8,216,512,27,729,0,1,343,125

第一趟排序:

 0     1    512   343   64   125   216   27    8   729

 0     1      2      3      4      5      6      7     8     9

第二趟排序:

8            729    

1    216   27

0    512   125         343           64

0     1      2      3      4      5      6      7     8     9

第三趟排序:

64

27

8

1

0    125   216  343         512          729

0     1      2      3      4      5      6      7     8     9

輸出:1  8  27  64  125  216  343  512  729

代碼:

import random
def radixSort():
    A=[random.randint(1,9999) for i in xrange(10000)]   
    for k in xrange(4):  #4輪排序       
        s=[[] for i in xrange(10)]
        for i in A:
            s[i/(10**k)%10].append(i)
        A=[a for b in s for a in b]
    return A

 1.3 計數排序

假設n個輸入元素中每一個都是介於0到k之間的整數,此處k為某個整數。當k=O(n)時,計數排序的運行時間為Θ(n)。

對每一個數的元素x,確定出小於x的元素個數。有了這一信息就可以把x直接放到最終輸出數組中的位置上。

def countingSort(alist,k):
    n=len(alist)
    b=[0 for i in xrange(n)]
    c=[0 for i in xrange(k+1)]
    for i in alist:
        c[i]+=1
    for i in xrange(1,len(c)):
        c[i]=c[i-1]+c[i]
    for i in alist:
        b[c[i]-1]=i
        c[i]-=1
    return b
if __name__=='__main__':
    a=[random.randint(0,100) for i in xrange(100)]
    print countingSort(a,100)

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM