十大基本排序算法
排序算法是《數據結構與算法》中最基本的算法之一。
排序算法可以分為內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。常見的內部排序算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸並排序、快速排序、堆排序、基數排序等。這里使用python實現這十大排序算法。
一、冒泡排序
算法步驟
比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最后一對。這步做完后,最后的元素會是最大的數。
針對所有的元素重復以上的步驟,除了最后一個。
持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
# 冒泡排序 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
二、選擇排序
算法步驟
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再從剩余未排序元素中繼續尋找最小(大)元素,然后放到已排序序列的末尾。
重復第二步,直到所有元素均排序完畢。
#選擇排序 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
三、插入排序
算法步驟
將第一待排序序列第一個元素看做一個有序序列,把第二個元素到最后一個元素當成是未排序序列。
從頭到尾依次掃描未排序序列,將掃描到的每個元素插入有序序列的適當位置。(如果待插入的元素與有序序列中的某個元素相等,則將待插入元素插入到相等元素的后面。)
# 插入排序 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
四、希爾排序
算法步驟
選擇一個增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
按增量序列個數 k,對序列進行 k 趟排序;
每趟排序,根據對應的增量 ti,將待排序列分割成若干長度為 m 的子序列,分別對各子表進行直接插入排序。僅增量因子為 1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。
# 希爾排序 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
五、歸並排序
算法步驟
1.申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合並后的序列;
2.設定兩個指針,最初位置分別為兩個已經排序序列的起始位置;
3.比較兩個指針所指向的元素,選擇相對小的元素放入到合並空間,並移動指針到下一位置;
4.重復步驟 3 直到某一指針達到序列尾;
5.將另一序列剩下的所有元素直接復制到合並序列尾。
#歸並排序 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
六、快速排序
算法步驟
1.從數列中挑出一個元素,稱為 "基准"(pivot);
2.重新排序數列,所有元素比基准值小的擺放在基准前面,所有元素比基准值大的擺在基准的后面(相同的數可以到任一邊)。在這個分區退出之后,該基准就處於數列的中間位置。這個稱為分區(partition)操作;
3.遞歸地(recursive)把小於基准值元素的子數列和大於基准值元素的子數列排序。
#快速排序 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,(int, float)) else right if left < right: partitionIndex = partition(arr, left, right) quickSort(arr, left, partitionIndex-1) quickSort(arr, partitionIndex+1, right) return arr def partition(arr, left, 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, i, j): arr[i], arr[j] = arr[j], arr[i]
七、堆排序
算法步驟
1.創建一個堆 H[0……n-1];
2.把堆首(最大值)和堆尾互換;
3.把堆的尺寸縮小 1,並調用 shift_down(0),目的是把新的數組頂端數據調整到相應位置;
4.重復步驟 2,直到堆的尺寸為 1。
#堆排序 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, i, largest) heapify(arr, largest) def swap(arr, i, j): arr[i], arr[j] = arr[j], arr[i] def heapSort(arr): global arrLen arrLen = len(arr) buildMaxHeap(arr) for i in range(len(arr)-1,0,-1): swap(arr,0,i) arrLen -=1 heapify(arr, 0) return arr
八、計數排序
算法步驟
1.找出待排序的數組中最大和最小的元素
2.統計數組中每個值為i的元素出現的次數,存入數組C的第i項
3.對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加)
4.反向填充目標數組:將每個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1
#計數排序 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
九、桶排序
算法步驟
桶排序是計數排序的升級版。它利用了函數的映射關系,高效與否的關鍵就在於這個映射函數的確定。為了使桶排序更加高效,我們需要做到這兩點:
- 在額外空間充足的情況下,盡量增大桶的數量
- 使用的映射函數能夠將輸入的 N 個數據均勻的分配到 K 個桶中
同時,對於桶中元素的排序,選擇何種比較排序算法對於性能的影響至關重要。
def bucketSort(arr): # 選擇一個最大的數 max_num = max(nums) # 創建一個元素全是0的列表, 當做桶 bucket = [0]*(max_num+1) # 把所有元素放入桶中, 即把對應元素個數加一 for i in nums: bucket[i] += 1 # 存儲排序好的元素 sort_arr = [] # 取出桶中的元素 for j in range(len(bucket)): if bucket[j] != 0: for y in range(bucket[j]): sort_nums.append(j) return sort_arr
十、基數排序
算法步驟
先排元素的最后一位,再排倒數第二位,直到所有位數都排完
#基數排序 def radix_sort(s): i = 0 # 記錄當前正在排拿一位,最低位為1 max_num = max(s) # 最大值 j = len(str(max_num)) # 記錄最大值的位數 while i < j: bucket_list =[[] for _ in range(10)] #初始化桶數組 for x in s: bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶數組 print(bucket_list) s.clear() for x in bucket_list: # 放回原序列 for y in x: s.append(y) i += 1
在學習python實現基礎算法時,在GitHub上找到一個使用python實現算法可視化,作者是真的厲害,有興趣的可以去看下。
這里附上鏈接:https://github.com/ZQPei/Sorting_Visualization