常見排序算法之python實現
本文介紹了幾種常用的排序算法,包含冒泡排序,選擇排序,插入排序,歸並排序,快速排序,堆排序,本文涉及的代碼可以在https://github.com/lianyingteng/Programming-practice上找到
1. 冒泡排序
時間復雜度為O(n^2), 穩定的排序算法
思路:一開始比較的區間是【0,n-1】,依次比較相鄰兩數,哪個數大哪個數就放在後面,這樣一次遍歷數組後,最大的數會在數組的最後一個位置,然後比較區間從【0,n-1】縮小到了【0,n-2】,在進行一次遍歷下來,第二大的數會被放在數組倒數第二的位置,依次類推。直到把範圍縮小到一個數的時候,數組就有序了。
def bubbleSort(arr):
length = len(arr) for i in range(length-1): #趟數 for j in range(length-i-1): #每趟元素數 if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr
2. 選擇排序
時間復雜度為O(n^2),不穩定的排序算法
思路:一開始從【0,n-1】選出一個最小值放在位置0上;第二次從【1,n-1】上選擇一個最小值放在位置1上;依次類推;直到數組訪問剩下一個元素時,數組有序了。
def selectionSort(arr): """選擇排序 """ length = len(arr) for i in range(length): min_i = i # 最小值索引 for j in range(i, length): if arr[min_i] > arr[j]: min_i = j arr[min_i], arr[i] = arr[i], arr[min_i] return arr
3. 插入排序*
時間復雜度為O(n^2),穩定的排序算法
註:當數組幾乎有序的情況下,時間復雜度為O(n*k),k為最多移動的距離;當數組逆序時,時間復雜度最大為O(n^2)
思路:把n個待排序的元素看成是一個有序表和一個無序表,開始時有序表只有一個元素,無序表有n-1個元素。排序過程中每次從無序表中取出一個元素,把它的排序碼依次與有序表中元素比較(後->前),將它插入有序表的適當位置,使之成為新的有序表。
def insertSort(arr): """插入排序 """ length = len(arr) for i in range(length-1): o_i = i # 有序表最後一個元素索引 u_v = arr[o_i+1] # 無序表的元素值 while o_i >= 0 and arr[o_i] > u_v: arr[o_i+1] = arr[o_i] o_i -= 1 arr[o_i+1] = u_v # 帶插入元素合適位置,+1是因為前面-1 return arr
4. 歸並排序*
時間復雜度為O(nlogn),穩定的排序算法
思路:首先讓數組每一個元素成為長度為1的有序區間;然後將兩個長度為1的有序區間進行合並,生成長度為2的有序區間;然後再將兩個長度為2的有序區間進行合並,生成長度為4的有序區間;依次類推,直至數組有序。1合2,2合4,4合8,8合16,……。
def mergerSort(arr): """歸並排序 劃分成左右兩部分; 兩兩合並,成有序數組 """ if len(arr) <= 1: return arr mid = len(arr) // 2 # 左右劃分, 生成長度為1的有序數組時開始返回 leftArr = mergerSort(arr[:mid]) rightArr = mergerSort(arr[mid:]) # 兩兩合並 return merger(leftArr, rightArr) def merger(left, right): """合並兩個有序數組,形成新的有序數組返回 """ res = [] l, r = 0, 0 while l < len(left) and r < len(right): if left[l] <= right[r]: res.append(left[l]) l += 1 else: res.append(right[r]) r += 1 res += left[l:] res += right[r:] return res
5. 快速排序**
時間復雜度為O(nlogn), 不穩定的排序算法
註:在數組完全無序的情況下,快排效果最好,為O(nlogn);在有序情況下效果最差,為O(n^2)。
思路:隨機排序 - 在數組中隨機選擇一個數,使得數組中大於它的數放在它的右邊、小於等於它的數放在它的左邊,然後左右兩邊的數遞歸的調用快排的過程。
快排的一次劃分過程 - 時間復雜度為O(n):
首先,我們隨機選擇數組中的一個作為劃分值;然後把劃分值與數組的最後一個元素進行交換,使得劃分值放到數組的最後一個位置(如b);然後我們定義一個小於等於區間,初始時,小於等於區間為空,放在數組的最左邊(如c);然後開始遍歷數組,如果元素大於劃分值,繼續遍歷下一個元素,如果元素值小於等於劃分值,就讓該元素與小於等於區間的下一個元素進行交換,擴增小於等於區間(如d,e);依次執行這個過程,直到數組中只剩一個數;然後數組最後一個數(劃分值)與小於等於區間的下一個數進行交換,快排的一次劃分過程就結束了(如f,g)。
def quickSort(arr, left, right): """快速排序 對left到right區間上的數組進行快排 """ if left >= right: return None midValue = arr[(left+right)//2] # 劃分值 l, r = left, right while l < r: while arr[l] < midValue: l += 1 while arr[r] > midValue: r -= 1 if l >= r: break arr[l], arr[r] = arr[r], arr[l] r -= 1 l += 1 if l == r: l += 1 r -= 1 if left < r: quickSort(arr, left, r) if right > l: quickSort(arr, l, right) return None
6. 堆排序
時間復雜度:O(nlogn),不穩定的排序算法,常用於查找top x
思路:首先將數組【0,n-1】區間上的所有元素構建大根堆,然後將堆頂元素與數組最後一個元素進行交換,這樣數組最後一個元素為最大值,作為數組有序部分存在下來;然後將數組【0,n-2】區間上的所有元素構建大根堆,然後執行堆頂元素與數組的倒數第二個元素進行交換,這樣數組後兩位元素分別是數組的最大值和第二大的值存在下來;然後將數組區間【0,n-3】區間構建大根堆,交換;重復以上過程直到數組有序。
def heapSort(arr): """堆排序 """ arr = buildMaxHeap(arr) for i in list(range(len(arr)))[::-1]: arr[0], arr[i] = arr[i], arr[0] adjustHeap(arr, 0, i) # n表示數組的大小(不是堆) return arr def buildMaxHeap(arr): """建立大根堆 從下向上構建 """ for i in list(range(len(arr)//2))[::-1]: adjustHeap(arr, i, len(arr)) return arr def adjustHeap(arr, start, size): """將數組[start:]調整成堆結構 參數 --- start: int 數組起始index size:int 數組大小 """ lChild = 2 * start + 1 rChild = 2 * start + 2 maxi = start if maxi < size//2: # 說明有孩子 if lChild < size and arr[lChild] > arr[maxi]: maxi = lChild if rChild < size and arr[rChild] > arr[maxi]: maxi = rChild if maxi != start: # == 說明已經是最大堆了,所以這裏不是 arr[maxi], arr[start] = arr[start], arr[maxi] adjustHeap(arr, maxi, size)
常見排序算法之python實現