1.選擇排序:
選擇法思路:先取一個元素進行與其後面的元素對比,如果後面的數據與這個數據的規律不符合,則記錄這個數據的位置,繼續對比,直到數據完畢,交換數據。
def select_sort(alist):
for i in range(len(alist)-1):
for j in range(i+1,len(alist)):
if alist[i]>alist[j]:
alist[i],alist[j]=alist[j],alist[i]
alist=[23,4,3,5,67,32,7,24]
select_sort(alist)
print(alist)
2.冒泡排序
冒泡排序原理: 每一趟只能將一個數歸位, 如果有n個數進行排序,只需將n-1個數歸位, 也就是說要進行n-1趟操作(已經歸位的數不用再比較)。
def bubble_sort(alist):
# 遍歷所有數組元素
for i in range(len(alist)):
for j in range(0, len(alist) - i - 1):
if alist[j]>alist[j+1]:
alist[j],alist[j+1]=alist[j+1],alist[j]
alist=[23,4,3,5,67,32,7,24]
bubble_sort(alist)
print(alist)
3.插入排序
具體實現步驟爲:首先我們把整個數組拆分爲有序區間和未排序區間,有序區間在插入排序一開始只有一個元素,就是數組的第一個元素。接在有序區間之後的一個元素就是準備插入的元素,在圖中就是標爲綠色的元素,在有序區間內尋找位置並插入。其尋找邏輯爲:從後往前依次進行比較,如果待插入元素大於當前元素,則將待插入元素插入到當前元素的後一位,如果待插入元素小於當前元素,則將當前元素後移一位。不斷重複該過程直至到數組的最後一位。
def insertion_sort(alist):
# 遍歷所有數組元素
for i in range(1,len(alist)):
key=alist[i]
j=i-1
while j>=0:
if alist[j] >key:
alist[j+1] = alist[j]
j-=1
else:
break
alist[j+1]=key
i+=1
alist=[23,4,3,5,67,32,7,24]
insertion_sort(alist)
print(alist)
4.快速排序:
思想:先從待排序的數組中找出一個數作爲基準數,然後將原來的數組劃分成兩部分:小於基準數的左子數組和大於等於基準數的右子數組。然後對這兩個子數組再遞歸重複上述過程,直到兩個子數組的所有數都分別有序。最後返回“左子數組” + “基準數” + “右子數組”,即是最終排序好的數組。
def quick_sort(alist, start, end):
if start >= end:
return
mid = alist[start]
left = start
right = end
# left與right未重合,就向中間移動
while left < right:
while left < right and alist[right] >= mid:
right -= 1
alist[left] = alist[right]
while left < right and alist[left] < mid:
left += 1
alist[right] = alist[left]
# 從循環退出後,left與right相遇,即left==right
alist[left] = mid
# 對左邊部分執行快速排序
quick_sort(alist, start, left-1)
# 對右邊部分執行快速排序
quick_sort(alist, left+1, end)
alist = [23,4,3,5,67,32,7,24]
quick_sort(alist, 0, len(alist) - 1)
print(alist)
【注】:
1.快速排序算法的平均時間複雜度爲O(nlogn),通常認爲在所有同數量級的排序算法中,快速排序的平均性能是最好的,這也是它被稱爲“快速排序”的原因。
2.快速排序算法相比於其他排序算法來說比較耗費空間資源,因爲快速排序需要棧空間來實現遞歸。
3.快速排序的基準元素的選取非常重要,如果基準元素選取不當,可能影響排序過程的時間複雜度和空間複雜度。爲了避免快速排序退化爲冒泡排序以及遞歸棧過深等問題,通常依照“三者取中”的法則來選取基準元素。三者取中法是指在當前待排序的子序列中,將其首元素、尾元素和中間元素進行比較,在三者中取中值作爲本趟排序的基準元素。
5.歸併排序:
思想:先遞歸分解數組,再合併數組
原理:將數組分解最小之後,然後合併兩個有序數組,基本思想是比較兩個數組的最前面的數,誰小就取誰,取完後,將相應的指針後移以爲。然後再比較,直到一個數組爲空,最後把另一個數組的剩餘部分複製過來即可。
def merge_sort(alist):
if len(alist) <= 1:
return alist
# 二分分解
num = len(alist) // 2
left = merge_sort(alist[:num])
right = merge_sort(alist[num:])
# 合併
return merge(left, right)
def merge(left, right):
'''合併操作,將兩個有序數組left[]和right[]合併成一個大的有序數組'''
# left與right的下標指針
l, r = 0, 0
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
return result
alist = [23,4,3,5,67,32,7,24]
sorted_alist = merge_sort(alist)
print(sorted_alist)
6.希爾排序:
def shellSort(alist):
# 設定步長
step = len(alist)//2
while step > 0:
for i in range(step, len(alist)):
# 類似插入排序, 當前值與指定步長之前的值比較, 符合條件則交換位置
while i >= step and alist[i-step] > alist[i]:
alist[i], alist[i-step] = alist[i-step], alist[i]
i -= step
step = step//2
return alist
alist = [23,4,3,5,67,32,7,24]
shellSort(alist)
print(shellSort(alist))
7.堆排序
思想:堆排序是簡單選擇排序的改進算法,簡單選擇排序在待排序的個數據中選擇一個最小的元素需要進行n-1次的比較,但是並沒有將每一次循環的結果保存下來,在下一次循環中,有很多比較已經在上一次的循環中做過了,但由於上一次循環時沒有保存這些比較結果,所以下一次循環時又要重複這些比較操作,因此數據的比較次數較多。堆排序可以做到每次在選擇最小記錄的同時,根據比較結果對其他元素做出相應的調整。
堆的特點就是FIFO(first in first out)先進先出,這裏的話我覺得可以理解成樹的結構。
堆在接收數據的時候先接收的數據會被先彈出。
棧的特性正好與堆相反,是屬於FILO(first in/last out)先進後出的類型。
棧處於一級緩存而堆處於二級緩存中。這個不是本文重點所以不做過多展開。
堆(定義):(二叉)堆數據結構是一個數組對象,可以視爲一棵完全二叉樹。如果根結點的值大於(小於)其它所有結點,並且它的左右子樹也滿足這樣的性質,那麼這個堆就是大(小)根堆。
def build_heap(alist):
"""建立一個堆"""
# 自底向上建堆
for i in range(len(alist) //2 - 1, -1, -1):
heap(alist, len(alist), i)
def heap(alist, heap_size, index):
"""調整列表中的元素以保證以index爲根的堆是一個最大堆"""
# 將當前結點與其左右子節點比較,將較大的結點與當前結點交換,然後遞歸地調整子樹
left_child = 2 * index + 1
right_child = left_child + 1
if left_child < heap_size and alist[left_child] > alist[index]:
largest = left_child
else:
largest = index
if right_child < heap_size and alist[right_child] > alist[largest]:
largest = right_child
if largest != index:
alist[index], alist[largest] = alist[largest], alist[index]
heap(alist, heap_size, largest)
def heapsort(alist):
"""堆排序"""
# 先將列表調整爲堆
build_heap(alist)
heap_size = len(alist)
# 調整後列表的第一個元素就是這個列表中最大的元素,將其與最後一個元素交換,然後將剩餘的列表再調整爲最大堆
for i in range(len(alist) - 1, 0, -1):
alist[i], alist[0] = alist[0], alist[i]
heap_size -= 1
heap(alist, heap_size, 0)
if __name__ == '__main__':
alist = [23, 4, 3, 5, 67, 32, 7, 24]
heapsort(alist)
print(alist)
8.基數排序
基數排序思想:基數排序的實現,是將原數組中的數值,分別按照個位,十位,百位......等的數值依次分組,比如,先按照個位數值分組,將原數組的元素按照個位數字進行依次分配,然後將分配好的元素,依次按照個位數字的大小依次存入到原數組中,然後再將該數組按照十位,百位....上的數字分組,最終實現排序。
基數排序(radix sort)屬於“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間複雜度爲O (nlog(r)m),其中r爲所採取的基數,而m爲堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法。
def radix_sort(alist):
"""基數排序"""
i = 0 # 記錄當前正在排拿一位,最低位爲1
max_num = max(alist) # 最大值
j = len(str(max_num)) # 記錄最大值的位數
while i < j:
bucket_list =[[] for _ in range(10)] #初始化桶數組
for x in alist:
bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶數組
alist.clear()
for x in bucket_list: # 放回原序列
for y in x:
alist.append(y)
i += 1
if __name__ == '__main__':
alist = [23,4,3,5,67,32,7,24]
radix_sort(alist)
print(alist)