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)