Python練手之6種經典排序演算法

來源:互聯網
上載者:User

  在入手了python之後,確實被它簡單的特性和上手容易度震驚過。不過python和c語言什麼的又確實存在很大的差別,習慣了c語言,使用python的時候多少還是有些不習慣。

  入手python一周左右了,為了熟悉和深化對python的理解,就把幾種經典的排序演算法拿來練手,順便強化一下自己的基礎知識。開始寫了,才發現自己寫出來的代碼問題還真不少,排序的結果總是有各種問題,看來真的是很久沒有用這些演算法寫過東西了,都忘了一些細節的東西了,汗哪。。。

 

  廢話不多說,開始練手吧。

  排序前需要給定一個資料集,這個用隨機數產生就好:

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename:randata.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import random<br />'''<br />隨機產生0~10000000之間的數值<br />'''<br />def getrandata(num):<br />a=[]<br />i=0<br />while i<num:<br />a.append(random.randint(0,10000000))<br />i+=1<br />return a<br /> 

  經典演算法之冒泡排序(Bubble sort):

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename:bubble_sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import randata<br />'''<br />演算法思想:每次從最後開始往前滾,鄰接元素兩兩相比,小元素交換到前面<br />第一輪迴圈把最小的元素上浮至第一個位置,第二小的元素上浮至第二個位置,依次類推<br />'''<br />def bubbleSort(a):<br />l=len(a)-2<br />i=0<br />while i<l:<br />j=l<br />while j>=i:<br />if(a[j+1]<a[j]):<br />a[j],a[j+1]=a[j+1],a[j]<br />j-=1<br />i+=1<br /> 

  經典演算法之直接插入排序(Insert sort):

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename: insert_sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import randata<br />'''<br />被注釋掉的部分是c語言數組普通的插入方式<br />未被注釋的部分則是使用python列表的插入和刪除特性改善的<br />'''<br />def insertSort(arr):<br />for i in range(1,len(arr)):<br />'''<br />tmp=arr[i]<br />j=i<br />while j>0 and tmp<arr[j-1]:<br />arr[j]=arr[j-1]<br />j-=1<br />arr[j]=tmp<br />'''<br />j=i<br />while j>0 and arr[j-1]>arr[i]:<br />j-=1<br />arr.insert(j,arr[i])<br />arr.pop(i+1)<br /> 

  經典演算法之希爾排序(Shell sort):

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename: shell_sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import randata<br />def shellSort(arr):<br />dist=len(arr)/2<br />while dist>0:<br />for i in range(dist,len(arr)):<br />tmp=arr[i]<br />j=i<br />while j>=dist and tmp<arr[j-dist]:<br />arr[j]=arr[j-dist]<br />j-=dist<br />arr[j]=tmp<br />dist/=2<br /> 

  希爾排序的名稱源於它的發明者Donald Shell,該演算法是衝破二次時間屏障的第一批演算法之一,不過,直到它最初被發現的若干年後才被證明了它的亞二次時間界。它通過比較相距一定間隔的元素來工作;各趟比較所用的距離隨著演算法的進行而減小,直到只比較相鄰元素的最後一趟排序為止。

 

  經典演算法之歸併排序(Merge sort):

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename: merge_sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import randata<br />'''<br />使用新分配的空間儲存合并得到的新列表<br />arr: 原始列表(數組)<br />s: 需合并的第一段空間起始點<br />m: 需合并的第二段空間起始點<br />e: 需合并的第二段空間結束點<br />'''<br />def mergeWithNewSpace(arr,s,m,e):<br />i,j=s,m<br />t=0<br />newArr=[]<br />while i<m and j<=e:<br />if(arr[i]<arr[j]):<br />newArr.append(arr[i])<br />i+=1<br />t+=1<br />else:<br />newArr.append(arr[j])<br />j+=1<br />t+=1<br />if i>=m:<br />t=0<br />for i in range(s,j):<br />arr[i]=newArr[t]<br />t+=1<br />else:<br />t=0<br />for i in range(i,m):<br />newArr.append(arr[i])<br />for i in range(s,e+1):<br />arr[i]=newArr[t]<br />t+=1<br />del newArr<br />def mergePassWithNewSpace(arr, n, d):<br />i=0<br />while i<(n-d) and i<(n+1-2*d):<br />mergeWithNewSpace(arr,i,i+d,i+2*d-1)<br />i=i+2*d<br />if i<n-d:<br />mergeWithNewSpace(arr,i,i+d,n-1)<br />else:<br />mergeWithNewSpace(arr,i-2*d,i,n-1)<br />def mergeSortWithNewSpace(arr):<br />d=1<br />while d<len(arr):<br />mergePassWithNewSpace(arr,len(arr),d)<br />d*=2<br />'''<br />不分配新的空間儲存合并得到的列表<br />而是使用原列表使用插入方式儲存<br />arr: 原始列表(數組)<br />s: 需合并的第一段空間起始點<br />m: 需合并的第二段空間起始點<br />e: 需合并的第二段空間結束點<br />被注釋掉的部分是c語言數組普通的插入方式<br />未被注釋的部分則是使用python列表的插入和刪除特性改善的<br />'''<br />def mergeWithoutNewSpace(arr,s,m,e):<br />i,j=s,m<br />while i<m and j<=e:<br />if arr[i]>arr[j]:<br />'''<br />tmp=arr[j]<br />k=j<br />while k>i:<br />arr[k]=arr[k-1]<br />k-=1<br />arr[i]=tmp<br />'''<br />arr.insert(i,arr[j])<br />arr.pop(j+1)<br />j+=1<br />m+=1<br />else:<br />i+=1<br />'''<br />arr: 原始列表(數組)<br />n: 數組大小<br />d: 區間大小<br />'''<br />def mergePassWithoutNewSpace(arr, n, d):<br />i=0<br />while i<(n-d) and i<(n+1-2*d):<br />mergeWithoutNewSpace(arr,i,i+d,i+2*d-1)<br />i=i+2*d<br />if i<n-d:<br />mergeWithoutNewSpace(arr,i,i+d,n-1)<br />else:<br />mergeWithoutNewSpace(arr,i-2*d,i,n-1)<br />def mergeSortWithoutNewSpace(arr):<br />d=1<br />while d<len(arr):<br />mergePassWithoutNewSpace(arr,len(arr),d)<br />d*=2<br /> 

  歸併排序演算法中,在合并兩個已排序的表時,通常的做法是建立一個大小等於它們之和的新表,用於儲存這兩個表合并的結果,然後把把合并後的表在拷貝回這兩個連續的表中。另外一個做法,也可以不分配新的空間儲存結果,而是使用插入排序的思想進行合并。

  使用分配空間合并的方式,時間複雜度為O(nlogn),使用插入合并的方式,時間複雜度為O(n^2),這裡採用python列表的插入和刪除機制,比c語言中數組整體往後挪動的插入方式(見注釋部分)要高效不少。

 

  經典演算法之堆排序:

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename:heap_sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />'''<br />大根堆:在一棵完全二叉樹中,對於任意節點,滿足性質arr[i]>=arr[2*i], arr[i]>=arr[2*i+1]<br />小根堆:在一棵完全二叉樹中,對於任意節點,滿足性質arr[i]<=arr[2*i], arr[i]<=arr[2*i+1]<br />'''<br />import randata<br />'''<br />假定除了start位置的頂點外,以start位置為root的這棵二叉樹是一個大根堆<br />向下調整start位置的節點至合適的位置,是的這棵樹重新恢複為一個大根堆<br />'''<br />def adjust(arr,start,size):<br />tmp=arr[start]<br />j=2*start+1<br />while j<size:<br />if j<size-1 and arr[j]<arr[j+1]:<br />j+=1<br />if tmp>=arr[j]:<br />break<br />arr[start]=arr[j]<br />start=j<br />j=2*j+1<br />arr[start]=tmp<br />'''<br />從一堆亂序的元素列表中建立大根堆<br />'''<br />def buildHeap(arr):<br />size=len(arr)<br />for i in range(size/2-1,-1,-1):<br />adjust(arr,i,size)<br />def heapSort(arr):<br />size=len(arr)<br />buildHeap(arr)<br />'''<br />建立大根堆後,第一個元素為列表的最大元素,將它跟最後一個元素交換,列表大小-1<br />重新調整列表為大根堆,重複此操作直到最後一個元素<br />'''<br />for i in range(size-1,0,-1):<br />arr[i],arr[0]=arr[0],arr[i]<br />adjust(arr,0,i)<br />

  堆排序的思路是建立在大根堆和小根堆的基礎上,具體步驟可以參見網上解釋以及上面的源碼。

 

  經典演算法之快速排序:

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename:quick_sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import randata<br />import sys<br />'''<br />這個函數的作用是,從區間的第一個,最後一個和最中間的位置上選出一個中間大小的值,並把它放置在區間的第一個位置上<br />這樣有效消除預排序的最壞情況<br />'''<br />def median(a,start,end):<br />center=(start+end)/2<br />if a[start]>a[center]:<br />a[start],a[center]=a[center],a[start]<br />if a[start]>a[end]:<br />a[start],a[end]=a[end],a[start]<br />if a[center]>a[end]:<br />a[center],a[end]=a[end],a[center]<br />a[start],a[center]=a[center],a[start]<br />def doSwap(a,start,end):<br />if start>=end:<br />return<br />i,j=start,end<br />median(a,start,end)<br />tmp=a[start]<br />while(True):<br />while(a[j]>tmp and i<j):<br />j-=1<br />if i<j:<br />a[i]=a[j]<br />i+=1<br />while(a[i]<tmp and i<j):<br />i+=1<br />if i<j:<br />a[j]=a[i]<br />j-=1<br />else:<br />break<br />a[i]=tmp<br />doSwap(a,start,i-1)<br />doSwap(a,j+1,end)<br />def quickSort(a):<br />#設定遞迴深度為10000000,放置資料量過大時超出遞迴最大深度發生exception<br />sys.setrecursionlimit(1000000)<br />doSwap(a,0,len(a)-1)<br /> 

  在這裡,快速排序演算法在選擇參考值的時候,採用了中值選取的方式,即從區間的第一個,最後一個和最中間的元素,這三個中選擇一個中間大小的作為參考值,把這個元素挪動至第一個位置。這個演算法可以有效消除快速排序中的最壞時間複雜度。

 

  寫出了演算法,總要有個東西來驗證,寫一個單獨的部分來執行這些演算法,輸出個演算法花費的時間值,並將他們的執行結果輸出至檔案中,用於檢驗執行結果是否正確。

  #-*- coding: utf-8 -*-<br />#!/usr/bin/python<br />#Filename:sort.py<br />#Author: Boyce<br />#Email: boyce.ywr@gmail.com<br />import time<br />import randata<br />import bubble_sort<br />import quick_sort<br />import heap_sort<br />import shell_sort<br />import merge_sort<br />import insert_sort<br />fileName='sort.dat'<br />size=10000<br />print '/nStart generate randam data...'<br />arr=randata.getrandata(size)<br />print 'Data generation finished.'<br />print 'Data size is %d, result will be save to file %s'%(size,fileName)<br />f=file(fileName,'w')<br />f.write("/nOriginal data:/n")<br />f.write(str(arr))<br />#使用python內建的timSort排序演算法<br />a=arr[:]<br />print '/nStart internal sort...'<br />t1=time.clock()<br />a.sort()<br />t2=time.clock()<br />print 'Internal sort finisehd. Time used=%fs'%(t2-t1)<br />f.write('/n/nInternal sort [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart quick sort...'<br />t1=time.clock()<br />quick_sort.quickSort(a)<br />t2=time.clock()<br />print 'Quick sort finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nQuick sort [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart heap sort...'<br />t1=time.clock()<br />heap_sort.heapSort(a)<br />t2=time.clock()<br />print 'Heap sort finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nHeap sort [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart shell sort...'<br />t1=time.clock()<br />shell_sort.shellSort(a)<br />t2=time.clock()<br />print 'Shell sort finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nShell sort [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart merge sort with new space...'<br />t1=time.clock()<br />merge_sort.mergeSortWithNewSpace(a)<br />t2=time.clock()<br />print 'Merge sort with new space finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nMerge sort with new space [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart merge sort without new space...'<br />t1=time.clock()<br />merge_sort.mergeSortWithoutNewSpace(a)<br />t2=time.clock()<br />print 'Merge sort without new space finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nMerge sort without new space [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart insert sort...'<br />t1=time.clock()<br />insert_sort.insertSort(a)<br />t2=time.clock()<br />print 'Insert sort finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nInsert sort [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />a=arr[:]<br />print '/nStart bubble sort...'<br />t1=time.clock()<br />bubble_sort.bubbleSort(a)<br />t2=time.clock()<br />print 'Bubble sort finished. Time used=%fs'%(t2-t1)<br />f.write('/n/nBubble sort [Time used=%fs]/n'%(t2-t1))<br />f.write(str(a))<br />del a<br />f.close()<br /> 

 

  這是某次執行的結果:

 

 

  輸出結果被儲存在目前的目錄的sort.dat檔案中,用記事本開啟即可看到。

  (看看人家python內建的timSort排序演算法,根本就不是一個數量級的,真牛,好快呀。。。)

 

  這就是輸出檔案的內容顯示:

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.