排序方法指的是對一個無序的數列,按照一定方法讓其變得有序。排序法重點是思維過程,本文中的四種排序方法都較為基礎,但其中蘊含的演算法思維各不相同,適合作為演算法入門學習內容。
- 選擇排序法
我認為選擇排序法是較符合一般人思維模式的排序法,它是指對於每個數列,從其中找出最小的一個數字,將其放至首位,然後再不斷對剩餘的無序數列重複此操作。當剩餘無序數列的長度為0時,則完成排序。其python實現程式碼如下:
點選檢視程式碼
def select_sort(my_list):
n= len(my_list) # n為數列長度
for i in range(n-1): # 共進行n-1次選擇(外迴圈),因為只要選出最小的n-1個數,最大的數就是剩下的,不需要進行額外操作天然已經位於數列末端
min_i = i # 初始化最小數字的索引為無序數列的第一個元素的索引,即假設第一個數字現在就是最小值。
for j in range(i+1,n): # 內迴圈處理無序數列中的每一個元素
if my_list[j]<my_list[min_i]: #一旦無序數列中的數字比我們假設的初始值小,就將其索引記錄下來
min_i = j
if min_i != i: # 一次內迴圈完成後,已經將無序數列中最小值的索引賦值給了min_i,如果其不同於無序數列的最左端(第一個)數字,則將兩者交換。交換完成後最小值已位於無序數列的最左段,此時可以將其視為有序數列的最右端,而不再是無序數列的一部分(透過外迴圈i的不斷增加來實現)
my_list[i],my_list[min_i] = my_list[min_i],my_list[i]
- 氣泡排序法
氣泡排序的過程是每次將最大的一個元素放至佇列末尾,這聽起來很像選擇排序的反過程。但是氣泡排序的實現是完全不同的。每一次排序,都是將無序數列的每一位,依次與其右邊的元素進行比較,並將其中較大的數字放在右邊。如此操作,大的數字會不斷被向右移,直至遇到比他更大的數字。這個更大的數字會接過其接力棒,再次向右進行比較,直到到達無序數列的最後一位。程式碼實現如下:
點選檢視程式碼
def bubble_sort(my_list):
listlen = len(my_list)
for i in range(listlen-1): # i 代表輪次,範圍為0到n-2共n-1次(最大的n-1個數字排完無需再排第n個)
for j in range(listlen-1-i): # j 為每輪進行比較的第一個數字,因為最後的i個數字已經完成了排序,所以每次都是比較(n-1)-i個數字即可。對於第一輪
if my_list[j]>my_list[j+1]: # 如果比右邊數字大,則進行交換
my_list[j],my_list[j+1]=my_list[j+1],my_list[j]
- 插入排序
插入排序是指將每個序列分為左右兩個部分,左邊是已經從小到大排序完成的數列,右邊是無序數列,依次將無序數列的第一位插入至有序數列中。對於一個未經過排序的數列,可以將第一個數字視作有序的(很顯然單獨一個數字必然是有序的),而將第二個數字開始的剩餘數字視為需要排序的無序數列。程式碼實現如下:
點選檢視程式碼
def insert_sort(my_list):
n = my_list
for i in range(1,n): # i 表示現在要處理第i個數字(第0)位不需要處理,在處理完這n-1個數字後它會天然出現在應該出現的位置
for j in range(i+1,0,-1): # j 指示要進行比較的數字,每次與左邊的數字進行比較,如果小於左邊數字說明應該左移
if my_list[j]<my_list[j-1]:
my_list[j],my_list[j-1] = my_list[j-1],my_list[j]
else:
break
- 快速排序
快速排序的邏輯很簡單,但是程式碼實現會稍微複雜一點。原理是:隨便選取一個數字,將數列中比其小的數字都放到它左側,比它大的數字都放在它右側,以此來確定其在數列中的位置;之後,再對於每個沒有確定下來的數列區間重複此操作,直至每個數字都位於正確的位置。快排使用了遞迴的方式去排序,程式碼實現如下:
點選檢視程式碼
def quick_sort(my_list,start,end):
"""
快速排序
:param my_list: 要排序的列表
:param start: 表示從哪個位置開始排序
:param end: 表示到哪個位置結束排序
:return: 如果start>=end,則表示排序完成,否則需要繼續排序
"""
if start >=end: # 當一個區間的長度為1或0時,說明已經排好序,則直接返回
return
left = start #左指標為區間的第一個元素
right = end #右指標
mid = my_list[start] # 選取第一個元素作為中間值(基準值)。此時左指標位置空出來了
while left < right: # 左右指標向中間移動,直到左右指標相遇
while my_list[right]>=my_list and left <right: # 右指標向左移動,直到遇到小於等於基準值的元素
right-=1
my_list[left] = my_list[right] # 將小於等於基準值的元素放到左指標位置
while my_list[left]<my_list and left <right: # 左指標向右移動,直到遇到大於等於基準值的元素
left+=1
my_list[right] = my_list[left] # 將大於等於基準值的元素放到右指標位置
my_list[left] = mid # 經過上述的兩次交換之後,可能存在兩種情況:1.左右指標相遇;2.左指標的值已經賦給了右指標的位置。無論哪種情況,都需要將基準值放到左指標的位置。
# 遞迴左半區間。如果 start=left-1,說明這次排序完之後左半區只有一個元素,不需要再排序。如果start>left-1,說明左半區為空,不需要再排序。
quick_sort(my_list,start,left-1)
quick_sort(my_list,right+1,end) # 遞迴右半區間