排序算法
定義:是一種能將一串數據依照特定的順序進行排列的一種算法。
1.冒泡排序
思路:比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。以此類推,對每一對相鄰元素做相同處理,從開始第一隊到結尾的最後一對。這不做完之後最後的元素就會是最大的數。然後對所有的元素進行重複以上的步驟,每次都出去最後的一個。
冒泡排序
無序的序列:[54,26,93,17,77,31,44,55,20]
第一次比較,54>26,交換:26,54, 93,17,77,31,44,55,20
第二次比較,54<93,不處理:26,54, 93,17,77,31,44,55,20
第三次比較,93>17, 交換:26,54, 17,93, 77,31,44,55,20
第四次比較,93>77, 交換:26,54, 17, 77, 93, 31,44,55,20
第五次比較,93>31, 交換:26,54, 17, 77, 31,93, 44,55,20
第六次比較,93>44, 交換:26,54, 17, 77, 31, 44,93, 55,20
第七次比較,93>55, 交換:26,54, 17, 77, 31, 44, 55,93, 20
第八次比較,93>20, 交換:26,54, 17, 77, 31, 44, 55, 20,93
小結:1、最大的數93排在了隊列的末尾
2、列表的長度n = 9,我們比較了n-1次
重複上面的過程:
26, 17,54, 31, 44, 55, 20, 77,93
小結:1、比較了n-2次
2、77放在了無序列表尾部
繼續:
17, 26, 31, 44, 54, 20,55, 77,93 # 比較了 n-3 ,把55放在了無序列表的尾部
17, 26, 31, 44, 20, 54,55, 77,93 # 比較了 n-4 ,把54放在了無序列表的尾部
17, 26, 31, 20, 44, 54,55, 77,93 # 比較了 n-5 ,把54放在了無序列表的尾部
17, 26, 20, 31, 44, 54,55, 77,93 # 比較了 n-6 ,把31放在了無序列表的尾部
17, 20, 26, 31, 44, 54,55, 77,93 # 比較了 n-7 ,把26放在了無序列表的尾部
17, 20, 26, 31, 44, 54,55, 77,93 # 比較了 n-8 ,得到一個有序的序列
總結:
相鄰元素兩兩比較把最大值排在無序序列尾部這個過程,要循環n-1
代碼實現:
def bubbling_order(lis):
for i in range(len(lis)-1, 0, -1):
for j in range(i):
if lis[j] > lis[j+1]:
lis[j], lis[j+1] = lis[j+1], lis[j]
return lis
listA = [32, 56, 6, 78, 44, 34, 45, 48]
print('冒泡排序:', bubbling_order(listA))
2.選擇排序
思路:首先在沒有排序的序列只能夠找到最大(小)元素,存放到排序序列的其實位置,再從剩餘未排序元素中繼續尋找最大(小)元素,放到已排序序列的末尾,重複以上操作,直到所有元素均以排序完成。
選擇排序
無序的序列:[54,26,93,17,77,31,44,55,20]
第一次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,54,26,93, 77,31,44,55,20
第二次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20,54,26,93, 77,31,44,55
第三次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20, 26,54, 93, 77,31,44,55
第四次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20, 26, 31,54, 93, 77, 44,55
第五次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 93, 77, 55
第六次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 93, 77, 55
第七次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 55, 93, 77
第八次,從無序序列中挑出一個最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 55, 77, 93
代碼實現:
# 選擇排序
def choice_order(lis):
n = len(lis)
for i in range(1, n):
min_index = i-1
for j in range(i, n):
if lis[j] < lis[min_index]:
min_index = j
if min_index != i-1:
lis[i-1], lis[min_index] = lis[min_index], lis[i-1]
return lis
listB = [34, 56, 89, 7, 43, 23, 73, 21]
print('選擇排序:', choice_order(listB))
3.插入排序
插入排序是一種簡單直觀的排序算法
思路:通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相對應位置並插入。
插入排序
無序的序列:[54,26,93,17,77,31,44,55,20]
第一次插入:[20,54,26,93,17,77,31,44,55]
第二次插入:[20,54,55,26,93,17,77,31,44]
第三次插入:[20,44,54,55,26,93,17,77,31]
第四次插入:[20,31,44,54,55,26,93,17,77]
第五次插入:[20,31,44,54,55,77,26,93,17]
第六次插入:[17,20,31,44,54,55,77,26,93]
第七次插入:[17,20,31,44,54,55,77, 93,26]
第八次插入:[17,20,26,31,44,54,55,77, 93]
總結:
待排序序列元素數 : n
插入的次數: n-1
代碼實現:
# 插入排序
def insert_order(lis):
n = len(lis)
for i in range(1, n):
for j in range(i, 0, -1):
if lis[j] < lis[j-1]:
lis[j], lis[j-1] = lis[j-1], lis[j]
# print(lis)
return lis
listC = [12, 45, 9, 39, 18, 89, 48, 59]
print('插入排序:', insert_order(listC))
4.快速排序
思路:快速排序又稱爲劃分交換排序,將要排序的數據分割成獨立的兩部分,其中一部分的所有數據逗比另外一部分所有數據都要小,然後在按照此方法對兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
快速排序
無序的序列:[54,26,93,17,77,31,44,55,20]
第一次快速排序,那第一個元素54作爲基準值,進行分割:
[26,17,31,44,20,54, 93,77,55]
經過第一次分割排序,基準值左邊的序列的所有元素都小於基準右邊序列的所有元素
對54 左邊的序列進行遞歸的分割:
拿26作爲基準值,進行分割:
[17,20,26, 31,44,54, 93,77,55]
對26 左邊的序列進行遞歸的分割:
拿17作爲基準值,進行分割:
[17,20,26, 31,44,54, 93,77,55]
對17 右邊的序列進行遞歸的分割:
右邊序列只有一個元素20,不能在分割,返回
對26 右邊的序列進行遞歸的分割:
拿31作爲基準值,進行分割:
[17,20,26, 31,44,54, 93,77,55]
31小於44,不處理
對54 右邊的序列進行遞歸的分割:
拿93作爲基準值,進行分割:
[17,20,26, 31,44,54, 77, 55,93]
對93 右邊的序列進行遞歸的分割:
拿77作爲基準值,進行分割:
[17,20,26, 31,44,54, 55, 77,93]
接下來,把整個序列進行排序:
[17,20,26, 31,44,54, 55, 77,93]
代碼實現:
# 快速排序
def quick_order(lis, start, end):
# 判斷low是否小於high,如果爲false直接返回
if start >= end:
return lis
mid = lis[start] # 設置基準值
low = start
high = end
while low < high:
# 如果列表後面的數比基準值大或者相等,則前移以爲直到有比基準值小點的數出現
while low < high and lis[high] >= mid:
high -= 1
# 找到就把索引[high]的值賦給第[low]個元素
lis[low] = lis[high]
# 基準值列表之前的做同樣處理
while low < high and lis[low] < mid:
low += 1
lis[high] = lis[low]
lis[low] = mid
quick_order(lis, start, low-1)
quick_order(lis, low+1, end)
return lis
listD = [23, 56, 5, 67, 81, 21, 41, 14]
print('快速排序:', quick_order(listD, 0, len(listD) - 1))
5.希爾排序
希爾排序是插入排序的一種。也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本。
思路:希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序,隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。
代碼實現:
# 希爾排序
def shell_order(lis):
n = len(lis)
gap = n//2 # 設置初始步長
while gap > 0:
# 按照步長進行插入排序
for i in range(gap, n):
j = i
# 進行插入排序
while j >= gap and lis[j-gap] > lis[j]:
lis[j-gap], lis[j] = lis[j], lis[j-gap]
j -= gap
gap = gap//2 # 設置新的步長 進行循環下一次
return lis
listE = [68, 34, 56, 7, 23, 75, 90, 54]
print('希爾排序:', shell_order(listE))
6.並歸排序
思路:
假如我們有一個n個數的數列,下標從0到n-1
首先是拆分的過程
1 、我們按照 n//2 把這個數列分成兩個小的數列
2 、把兩個小數列 再按照新長度的一半 把每個小數列都分成兩個更小的
3、一直這樣重複,一直到每一個數列包含單個元素之後是合併排序的過程:
3、按照最後分開的兩個數比較大小並合併成有序的數組
4 、對每組數據按照上次分開的結果,進行排序並合併成更大的數組
5、最後的到一個有序的數組
歸併排序
無序的序列:[54,26,93,17,77,31,44,55,20]
拆分過程:
第一次拆分,n = 9 n//2 = 4
拆分結果:[54,26,93,17]和[77,31,44,55,20]
遞歸拆分[54,26,93,17]的部分:
n = 5 n//2 = 2
拆分結果:[54,26]和[93,17]
遞歸拆分[54,26]的部分:
n = 2 n//2 = 1
拆分結果:[54]和[26]
合併[54]和[26],合併的結果 [26,54]
遞歸拆分[93,17]的部分:
n = 2 n//2 = 1
拆分結果:[93]和[17]
合併[93]和[17],合併的結果[17, 93]
合併left=[26,54]和right=[17, 93]
創建results =[]
定義兩個指針 lp=0,rp=0
比較left[lp]和right[rp] , 26>17
把17添加到results中,result.append(right[rp])
results=[17]
rp+=1 rp = 1
比較left[lp]和right[rp] , 26<93
把26添加到results中,result.append(left[lp])
results=[17,26]
lp+=1 lp =1
比較left[lp]和right[rp] , 54<93
把54添加到results中,result.append(left[lp])
results=[17,26,54]
lp+=1 lp=2
把93添加到results中,result.append(right[rp])
results=[17,26,54, 93]
返回results
遞歸拆分[77,31,44,55,20]的部分:
同樣的道理,遞歸拆分合並,
得到結果: [20,31, 44, 55,77]
合併left=[17,26,54, 93]和right=[20,31, 44, 55,77]
定義results = []
定義lp=0和rp =0
比較left[lp]和right[rp] , 17<20
把17添加到results中,result.append(left[lp])
results=[17]
lp+=1 lp = 1
比較left[lp]和right[rp] , 26>20
把20添加到results中,result.append(right[rp])
results=[17,20]
rp+=1
比較left[lp]和right[rp] , 26<31
把26添加到results中,result.append(left[lp])
results=[17,20,26]
lp+=1 lp = 2
。。。。。
最終結果:
[17, 20,26, 31, 44, 54, 55,77, 93]
代碼實現:
def merger_order(lis):
if len(lis) <= 1:
return lis
else:
num = len(lis)//2
left_part = merger_order(lis[:num])
right_part = merger_order(lis[num:])
return merger(left_part, right_part)
def merger(left, right):
h, r = 0, 0
result = []
while h < len(left) and r < len(right):
if left[h] < right[r]:
result.append(left[h])
h += 1
else:
result.append(right[r])
r += 1
result += left[h:]
result += right[r:]
return result
listF = [29, 4, 44, 52, 21, 42, 78, 25]
print('歸併排序:', shell_order(listF))