最近在複習軟考,把看到的排序算法整理了一下,之所以用python寫,是因爲python寫起來簡單....好吧,後來寫的時候發現有些地方用C寫還方便些。python雖然簡潔,但用起來效率感覺還是有些低,不過這不是重點啦。。。
1.代碼與說明
# -*- coding: utf-8 -*-
def bubbleSort(Data):
'''冒泡排序: 時間複雜度最好O(n),平均O(n*n),最壞O(n*n),輔助空間 O(1),算法穩定
n個數,每次從第一個數開始和相鄰的數比較,將大的冒泡到後面去。第一趟將最大的冒泡到最後,
然後第二次只需比較0~n-1,將其中最大的冒泡到n-1,依次下去...總共進行n-1趟排序即可
'''
if Data:
for i in range(len(Data)):
for j in range(len(Data)-i-1):
if Data[j]>Data[j+1]:
Data[j],Data[j+1]=Data[j+1],Data[j]
return Data
def quickSort(Data,low,high):
'''快速排序:O(n*logn),O(n*logn),O(n*n),O(n*logn),不穩定
冒泡的改進,被認爲是當前最優秀的內部排序算法(當然這也不是絕對的,還要看具體情況)。實現基於分治法:分解-解決-合併。
基本思想:
1.從數列中取出一個基數,
2.將數列中比他大的放在右邊,小的在左邊。
3.兩邊區間重複2,直到各區間只有一個數。
整個算法中的基數就是個坑,跳來跳去,總之比他小始終放一邊,大的放另一邊就行
參考:http://blog.csdn.net/morewindows/article/details/6684558
'''
if low < high:
left,right,base=low,high,Data[low]
while left <right:
#從後往前找比base小的數
while left <right and Data[right] >=base:
right-=1
if left < right:
Data[left]=Data[right]
#left+=1 這裏直接+1更快,因爲Data[left]必然小於base,下次循環不用算
#從前往後找比base大的數
while left <right and Data[left] < base:
left+=1
if left <right:
Data[right]=Data[left]
#right-=1
#left=right時一趟循環終止,base填回坑裏去
Data[left]=base
quickSort(Data,low,left-1) #遞歸左邊
quickSort(Data,left+1,high) #遞歸右邊
def insertSort(Data):
'''插入排序: 時間複雜度最好O(n),平均O(n*n),最壞O(n*n),輔助空間 O(1),算法穩定
如果Data不爲空則開始比較。Data[0]~Data[j]是排好的序列L1,key是未排待插入數據
如果key小於L1的最大值則將進行插入操作,while循環找到比key小的index並將key插入
在index後面。while循環用來尋找插入位置並將比key大的數後移,如果key本身比L1的
最大值還大則無需插入,直接for循環比較下一個
'''
if Data:
for i in range(1,len(Data)):
key,j = Data[i],i-1
while j>=0 and Data[j] > key:
Data[j+1]=Data[j]
j-=1
Data[j+1]=key
return Data
def selectSort(Data):
'''選擇排序: 時間複雜度最好O(n*n),平均O(n*n),最壞O(n*n),輔助空間 O(1),算法不穩定
n個數,每一趟從待排序列L2中選擇最大(或最小)數順序放在已排好序列L1後面(或前面)
總共經過n-1趟可排好,與插入排序相比,都是將數據分爲已排和未排序列並將未排元素整理
到已排序列中,不同的是插入排序在未排序列中按序整理,選排則是按大小選擇整理。
'''
if Data:
for i in range(len(Data)-1):
minnum=i
for j in range(i+1,len(Data)):#在L2中尋找最小值
if Data[j]<Data[minnum]:
minnum=j
if minnum != i:#如果找到直接交換,插入在L1後面
Data[i],Data[minnum]=Data[minnum],Data[i]
return Data
def shellSort(Data):
'''希爾排序: 時間複雜度最好未知,平均O(pow(n,1.25),最壞未知,輔助空間 O(1),不穩定
插入排序的改進,將數據分組,每組m個(m叫步長)每次對每組的第i個元素排序,
然後再分組,再排序,直到步長爲1.至於分組的方法需要理論推導,此處每次步長都取n/2減半
更好的步長選擇方法見wiki:http://zh.wikipedia.org/wiki/希爾排序
其他實現方法:http://blog.csdn.net/morewindows/article/details/6668714
'''
n=len(Data)
if n > 1:
gap=n/2
while gap > 0:
for i in range(gap):#按步長插入排序
for j in range(i+gap,n,gap):
if Data[j] < Data[j-gap]:
key = Data[j]
k=j-gap
while k >=0 and Data[k] > key:
Data[k+gap]=Data[k]
k-=gap
Data[k+gap]=key
gap/=2
return Data
if __name__ =="__main__":
Data=[3,5,1,56,3,7,34,21,8]
print Data
#insertSort(Data)
#bubbleSort(Data)
#selectSort(Data)
#shellSort(Data)
quickSort(Data,0,len(Data)-1)
print Data
2.python內置排序
3.瞎扯
1.內部排序是指待排序列完全存放在內存中進行的排序,適合不太大的序列。包括
插入排序(直接插入排序)
快速排序
選擇排序(簡單選擇排序)
冒泡排序
希爾排序
堆排序
歸併排序
2.外部排序指能處理大量數據的排序算法,數據不能一次裝入內存,通常要藉助外存儲器。常採用排序-歸併策略,比如外歸併排序。詳情參考wiki:http://zh.wikipedia.org/wiki/外排序
3.python中沒有自增和自減運算,這在寫代碼的時候異常不方便。當然咯,這也與python的設計目標有關係。python的設計哲學是優雅,明確、簡單。他們可能認爲這樣不太優雅,不利於代碼的可讀性,譬如js也不推薦使用++和--。另外一個原因,那就是python不提供像C那樣直接操作內存的功能。當執行a+=1時,C會直接修改a在內存中的值,而python則會在內存中新建一個整型變量(也不完全這樣,有些小數據python會複用,見下面第4點),然後讓a指向它。所以如果要執行a++,C語言中a還是那個a,而python中的a已經不是原來的a了,這樣就亂套了!
說到這裏,再扯一下python中的可變對象和不可變對象。python中所有對象都是值的引用。不可變指的是值不可變。要修改變量的值就要在內存中新建一個值並讓變量指向它,原來的如果不用就會被GC回收。可變對象不需要在其他地方申請內存,直接在自己後面申請/釋放空間即可,原地址不變。
4.對於小數值整型對象,比如1~100,python虛擬機在啓動時會先在內存中生成好,放在緩衝區以便於快速調用。看下面的例子:
開始a,b爲100,a is b是True,說明a,b指向內存中同一個對象,後面值變大了,a=100000時python會在內存中新建一個對象,b=100000也會新建一個對象,所以a,b指向不同對象,故爲False。id(a)是查看a的地址。
5.有關for循環,實質上是一個遍歷,for i in range(0,10),range()會生成一個0到9的list讓i遍歷。這樣就有一個缺陷:i在循環前每一步的值是確定的,不能動態改變。而在C語言中,for(int i=n/2,i>0,i=i/2),i是隨着循環每次都會改變的。不過事實上,i的值在循環前也是可以推算出來的,因此肯定是可以用python的for循環代替C的for(int i=n/2,i>0,i=i/2),只不過LZ還沒想到,誰知道還麻煩說一聲,哈哈!