10個python3常用排序演算法詳細說明與例項(快速排序,氣泡排序,桶排序,基數排序,堆排序,希爾排序,歸併排序,計數排序)
我簡單的繪製了一下排序演算法的分類,藍色字型的排序演算法是我們用python3實現的,也是比較常用的排序演算法。
Python3常用排序演算法
1、Python3氣泡排序——交換類排序
氣泡排序(Bubble Sort)也是一種簡單直觀的排序演算法。
它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。
走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢"浮"到數列的頂端。
作為最簡單的排序演算法之一,氣泡排序給我的感覺就像Abandon在單詞書裡出現的感覺一樣,每次都在第一頁第一位,所以最熟悉。
氣泡排序還有一種優化演算法,就是立一個 flag,當在一趟序列遍歷中元素沒有發生交換,則證明該序列已經有序。
但這種改進對於提升效能來說並沒有什麼太大作用。
最快:當輸入的資料已經是正序時(都已經是正序了,我還要你氣泡排序有何用啊)
最慢:當輸入的資料是反序時(寫一個 for 迴圈反序輸出資料不就行了,幹嘛要用你氣泡排序呢,我是閒的嗎)
Python3氣泡排序例項程式碼
# 氣泡排序 def bubbleSort(arr): for i in range(1,len(arr)): for j in range(0,len(arr)-i): if arr[j] > arr[j+1]: arr[j],arr[j + 1] = arr[j + 1],arr[j] return arr if __name__ == '__main__': list = [1,5,8,123,22,54,7,99,300,222] print("List source is:",list) result = bubbleSort(list) print("List sort is:",result)
效果
2、Python3快速排序-交換類排序
快速排序是由東尼·霍爾所發展的一種排序演算法。
在平均狀況下,排序 n 個專案要 Ο(nlogn) 次比較。在最壞狀況下則需要 Ο(n2) 次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他 Ο(nlogn) 演算法更快,因為它的內部迴圈(inner loop)可以在大部分的架構上很有效率地被實現出來。
快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分為兩個子序列(sub-lists)。
快速排序又是一種分而治之思想在排序演算法上的典型應用。本質上來看,快速排序應該算是在氣泡排序基礎上的遞迴分治法。
快速排序的名字起的是簡單粗暴,因為一聽到這個名字你就知道它存在的意義,就是快,而且效率高!它是處理大資料最快的排序演算法之一了。
特點:選基準、分治、遞迴
Python3快速排序-交換類排序例項原始碼
# 快速排序 def quickSort(arr,left=None,right=None): left = 0 if not isinstance(left,(int,float)) else left right = len(arr)-1 if not isinstance(right,float)) else right if left < right: partitionIndex = partition(arr,left,right) quickSort(arr,partitionIndex-1) quickSort(arr,partitionIndex+1,right) return arr def partition(arr,right): pivot = left index = pivot+1 i = index while i <= right: if arr[i] < arr[pivot]: swap(arr,i,index) index+=1 i+=1 swap(arr,pivot,index-1) return index-1 def swap(arr,j): arr[i],arr[j] = arr[j],arr[i] if __name__ == '__main__': list = [1,list) result = quickSort(list) print("List sort is:",result)
Python3快排簡寫
def quickSort2(array): return array if len(array) <= 1 else quickSort2([lt for lt in array[1:] if lt < array[0]]) + array[0:1] + quickSort2([ge for ge in array[1:] if ge >= array[0]])
效果
3、Python3選擇排序-選擇類排序
選擇排序是一種簡單直觀的排序演算法。
無論什麼資料進去都是 O(n2) 的時間複雜度。所以用到它的時候,資料規模越小越好。唯一的好處可能就是不佔用額外的記憶體空間了吧。
Python3選擇排序-選擇類排序例項原始碼
# 選擇排序 def selectionSort(arr): for i in range(len(arr) - 1): # 記錄最小數的索引 minIndex = i for j in range(i + 1,len(arr)): if arr[j] < arr[minIndex]: minIndex = j # i 不是最小數時,將 i 和最小數進行交換 if i != minIndex: arr[i],arr[minIndex] = arr[minIndex],arr[i] return arr if __name__ == '__main__': list = [1,list) result = selectionSort(list) print("List sort is:",result)
效果
4、Python3堆排序-選擇類排序
堆排序(Heapsort)是指利用堆這種資料結構所設計的一種排序演算法。
堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。堆排序可以說是一種利用堆的概念來排序的選擇排序。分為兩種方法:
1、大頂堆(大根堆):每個節點的值都大於或等於其子節點的值,在堆排序演算法中用於升序排列;
2、小頂堆(小根堆):每個節點的值都小於或等於其子節點的值,在堆排序演算法中用於降序排列;
堆排序的平均時間複雜度為 Ο(nlogn)。
Python3堆排序-選擇類排序例項原始碼
# 堆排序 def buildMaxHeap(arr): import math for i in range(math.floor(len(arr)/2),-1,-1): heapify(arr,i) def heapify(arr,i): left = 2*i+1 right = 2*i+2 largest = i if left < arrLen and arr[left] > arr[largest]: largest = left if right < arrLen and arr[right] > arr[largest]: largest = right if largest != i: swap(arr,largest) heapify(arr,largest) def swap(arr,arr[i] def heapSort(arr): global arrLen arrLen = len(arr) buildMaxHeap(arr) for i in range(len(arr)-1,-1): swap(arr,i) arrLen -=1 heapify(arr,0) return arr if __name__ == '__main__': list = [1,list) result = heapSort(list) print("List sort is:",result)
效果
5、Python3插入排序-插入類排序
插入排序是一種最簡單直觀的排序演算法。
插入排序的程式碼實現雖然沒有氣泡排序和選擇排序那麼簡單粗暴,但它的原理應該是最容易理解的了,因為只要打過撲克牌的人都應該能夠秒懂。
它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。
插入排序和氣泡排序一樣,也有一種優化演算法,叫做拆半插入。
Python3插入排序-插入類排序例項原始碼
# 作者:沙振宇 # 插入排序 def insertionSort(arr): for i in range(len(arr)): preIndex = i-1 current = arr[i] while preIndex >= 0 and arr[preIndex] > current: arr[preIndex+1] = arr[preIndex] preIndex-=1 arr[preIndex+1] = current return arr if __name__ == '__main__': list = [1,list) result = insertionSort(list) print("List sort is:",result)
效果
6、Python3希爾排序-插入類排序
希爾排序,也稱遞減增量排序演算法,是插入排序的一種更高效的改進版本。
但希爾排序是非穩定排序演算法。
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
1、插入排序在對幾乎已經排好序的資料操作時,效率高,即可以達到線性排序的效率;
2、但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位;
希爾排序的基本思想是:
先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄"基本有序"時,再對全體記錄進行依次直接插入排序。
Python3希爾排序-插入類排序例項原始碼
# 作者:沙振宇 # 希爾排序 def shellSort(arr): import math gap=1 while(gap < len(arr)/3): gap = gap*3+1 while gap > 0: for i in range(gap,len(arr)): temp = arr[i] j = i-gap while j >=0 and arr[j] > temp: arr[j+gap]=arr[j] j-=gap arr[j+gap] = temp gap = math.floor(gap/3) return arr if __name__ == '__main__': list = [1,list) result = shellSort(list) print("List sort is:",result)
效果
7、Python3歸併排序-歸併類排序
歸併排序(Merge sort)是建立在歸併操作上的一種有效的排序演算法。
該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
作為一種典型的分而治之思想的演算法應用,歸併排序的實現由兩種方法:
1、自上而下的遞迴(所有遞迴的方法都可以用迭代重寫,所以就有了第 2 種方法);
2、自下而上的迭代;
和選擇排序一樣,歸併排序的效能不受輸入資料的影響,但表現比選擇排序好的多,因為始終都是 O(nlogn) 的時間複雜度。代價是需要額外的記憶體空間
Python3歸併排序-歸併類排序例項原始碼
# 作者:沙振宇 # 歸併排序 def mergeSort(arr): import math if(len(arr)<2): return arr middle = math.floor(len(arr)/2) left,right = arr[0:middle],arr[middle:] return merge(mergeSort(left),mergeSort(right)) def merge(left,right): result = [] while left and right: if left[0] <= right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) while left: result.append(left.pop(0)) while right: result.append(right.pop(0)) return result if __name__ == '__main__': list = [1,list) result = mergeSort(list) print("List sort is:",result)
效果
8、Python3計數排序-分佈類排序
計數排序的核心在於將輸入的資料值轉化為鍵儲存在額外開闢的陣列空間中。
作為一種線性時間複雜度的排序,計數排序要求輸入的資料必須是有確定範圍的整數。
當輸入的元素是 n 個 0 到 k 之間的整數時,它的執行時間是 Θ(n + k)。計數排序不是比較排序,排序的速度快於任何比較排序演算法。
由於用來計數的陣列C的長度取決於待排序陣列中資料的範圍(等於待排序陣列的最大值與最小值的差加上1),這使得計數排序對於資料範圍很大的陣列,需要大量時間和記憶體。例如:計數排序是用來排序0到100之間的數字的最好的演算法,但是它不適合按字母順序排序人名。但是,計數排序可以用在基數排序中的演算法來排序資料範圍很大的陣列。
通俗地理解,例如有 10 個年齡不同的人,統計出有 8 個人的年齡比 A 小,那 A 的年齡就排在第 9 位,用這個方法可以得到其他每個人的位置,也就排好了序。當然,年齡有重複時需要特殊處理(保證穩定性),這就是為什麼最後要反向填充目標陣列,以及將每個數字的統計減去 1 的原因。
Python3計數排序-分佈類排序例項原始碼
# 作者:沙振宇 # 計數排序 def countingSort(arr,maxValue): bucketLen = maxValue+1 bucket = [0]*bucketLen sortedIndex =0 arrLen = len(arr) for i in range(arrLen): if not bucket[arr[i]]: bucket[arr[i]]=0 bucket[arr[i]]+=1 for j in range(bucketLen): while bucket[j]>0: arr[sortedIndex] = j sortedIndex+=1 bucket[j]-=1 return arr if __name__ == '__main__': list = [1,list) result = countingSort(list,max(list)) print("List sort is:",result)
效果
9、Python3基數排序-分佈類排序
基數排序是一種非比較型整數排序演算法。
其原理是將整數按位數切割成不同的數字,然後按每個位數分別比較。由於整數也可以表達字串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是隻能使用於整數。
python3基數排序-分佈類排序例項原始碼
# 作者:沙振宇 # 基數排序 def radix_sort(arr): """基數排序""" i = 0 # 記錄當前正在排拿一位,最低位為1 max_num = max(arr) # 最大值 j = len(str(max_num)) # 記錄最大值的位數 while i < j: bucket_list =[[] for _ in range(10)] #初始化桶陣列 for x in arr: bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶陣列 arr.clear() for x in bucket_list: # 放回原序列 for y in x: arr.append(y) i += 1 return arr if __name__ == '__main__': list = [1,list) result = radix_sort(list) print("List sort is:",result)
效果
Python3桶排序-分佈類排序
桶排序是計數排序的升級版。
它利用了函式的對映關係,高效與否的關鍵就在於這個對映函式的確定。為了使桶排序更加高效,我們需要做到這兩點:
1、在額外空間充足的情況下,儘量增大桶的數量
2、使用的對映函式能夠將輸入的 N 個數據均勻的分配到 K 個桶中
同時,對於桶中元素的排序,選擇何種比較排序演算法對於效能的影響至關重要。
最快:當輸入的資料可以均勻的分配到每一個桶中。
最慢:當輸入的資料被分配到了同一個桶中。
Python3桶排序-分佈類排序例項原始碼
# 作者:沙振宇 # 桶排序 def bucketSort(arr): # 選擇一個最大的數 max_num = max(arr) # 建立一個元素全是0的列表,當做桶 bucket = [0] * (max_num + 1) # 把所有元素放入桶中,即把對應元素個數加一 for i in arr: bucket[i] += 1 # 儲存排序好的元素 sort_nums = [] # 取出桶中的元素 for j in range(len(bucket)): if bucket[j] != 0: for y in range(bucket[j]): sort_nums.append(j) return sort_nums if __name__ == '__main__': list = [1,list) result = bucketSort(list) print("List sort is:",result)
效果
本文主要講解了10個python3常用排序演算法詳細說明與例項,更多關於python排序演算法的知識請檢視下面的相關連結