python版本排序演算法
一個推薦的部落格,裡面有詳細的動圖介紹。
排序演算法 | 平均時間複雜度 | 最壞時間複雜度 | 最好時間複雜度 | 空間複雜度 | 穩定性 |
---|---|---|---|---|---|
快速排序 | 不穩定 | ||||
氣泡排序 | 穩定 | ||||
插入排序 | 穩定 | ||||
選擇排序 | 不穩定 | ||||
歸併排序 | 穩定 | ||||
希爾排序 | 不穩定 | ||||
堆排序 | 不穩定 |
快速排序
思想:
通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分進行排序,也就是分治法的思想。
步驟:
- 從數列中挑選出一個元素,作為基準
- 重新遍歷數列,將比基準小的放在前面,比基準大的放在後面,相同的可以放在任意一邊
- 然後對剛才左邊的和右邊的,分別遞迴上面的操作
不穩定,這個時候不是雙重迴圈,時間複雜度O(nlogn).
# ------ coding:utf-8 -----
'''
快速排序
從陣列中選擇一個數作為基準,然後將陣列分成三部分,小於、等於、大於這個基準的
然後對小於、大於基準的陣列重複上面的操作
O(nlogn),不穩定
'''
def quickSort(nums):
if len(nums) <= 1:
return nums
base = nums[0]
left = []
equal = []
right = []
for num in nums:
if num < base:
left.append(num)
elif num > base:
right.append(num)
else:
equal.append(num)
left = quickSort(left)
right = quickSort(right)
return left + equal + right
print quickSort([2,3,1,9,0,4,7,8,5])
還有另外一種常見的原地排序的實現方法:
def quickSort2(nums, left, right):
if left >= right:
return
low = left
high = right
base = nums[left]
while left < right:
while left < right and nums[right] > base:
right -= 1
nums[left] = nums[right]
while left < right and nums[left] <= base:
left += 1
nums[right] = nums[left]
nums[right] = base
quickSort2(nums, low, left-1)
quickSort2(nums, left+1, high)
氣泡排序
思想:
重複走訪待排的序列,一次比較兩個元素,比如它們之間的順序錯誤了,就把它們進行交換。氣泡排序就是把小的元素往前調,把大的元素往後調。經過一次迴圈之後,最大的值將出現在最後。注意的是相鄰的兩個元素進行比較,而且是否需要交換也發生在這兩個元素之間。
步驟:
- 比較相鄰元素,如果第一個比第二個大,則交換它們
- 重複,直到序列末尾,這個時候序列最後的元素就是最大的數
- 重複,直到排序完成
當此次迴圈中,沒有元素交換的時候,就停止,代表排序完成
如果兩個元素相等,是不會去交換位置的。所以即使通過前面的兩輛交換把兩個元素放在的一起,也不會交換他們的位置,所以氣泡排序是穩定的。雙重迴圈,時間複雜度O(n2).
# ------- coding:utf-8 ----
'''
氣泡排序
將大的元素向後調,則一次機就將最大的元素放在了最後
時間複雜度是O(n^2),穩定
'''
def bubbleSort(nums):
# 外層迴圈控制從頭到尾的次數
for i in range(len(nums)-1):
count = 0 # 記錄一次迴圈中,交換元素的次數,如果為0的話,就停止了
# 內層迴圈控制走一次的過程
for j in range(len(nums)-1-i):
if nums[j] > nums[j+1]:
nums[j], nums[j+1] = nums[j+1], nums[j]
count += 1
if count == 0:
break
return nums
print bubbleSort([1,2,7,8,3,1,9,0,5])
插入排序
思想:
通過構建有序序列,對於未排序資料,在已排序序列中,從後向錢掃描,找到相應的位置進行並插入。
步驟:
- 從第一個元素開始,這個時候是一個有序序列
- 取出下一個元素,在已經排序的序列中,從後向前掃描,如果有序序列中的當前元素大於待排元素,則該元素後移一個位置,直到找到有序序列中的元素小於等於待排元素,就在該位置進行插入(可能找不到這樣的元素,則就在最前的位置插入)
- 重複上面的步驟,直到沒有待排元素
相等元素的前後順序沒有改變,所以插入排序是穩定的。雙重迴圈,時間複雜度O(n2).
# ------ coding:utf-8 -----
'''
插入排序
在已經有序的小序列的基礎上,一次插入一個元素。最初狀態只有1個元素
O(n^2),穩定
'''
def insertSort(nums):
n = len(nums)
for i in range(1, n):
# 將當前元素放到前面有序序列的正確位置
for j in range(i, 0, -1):
# 如果當前當前元素比前面的元素小,則往前移動,與前面的元素交換
if nums[j] < nums[j-1]:
nums[j], nums[j-1] = nums[j-1], nums[j]
else:
break
return nums
print insertSort([1,2,8,9,0,3,6,7,4])
選擇排序
思想:
首先在未排序的序列中找到最小的元素,存放在已排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小元素,然後放到已排序序列末尾。
選擇排序即是給每個位置選擇待排序元素中當前最小的元素。比如給第一個位置選擇最小的,在剩餘元素裡面給第二個位置選擇次小的。以此類推,直到第n-1個元素,第n個元素就不用選擇了。
舉例:5 8 5 2 9,首先會將5與2進行交換,那麼兩個5的順序就交換了,所以,選擇排序不穩定。
雙重迴圈,時間複雜度O(n2).
# ------ coding:utf-8 -------
'''
選擇排序
給每個位置選擇待排序中當前最小的元素(交換)
O(n^2),不穩定
'''
def selectSort(nums):
n = len(nums)
for i in range(n-1):
min_dix = i
for j in range(i+1, n):
# 尋找最小元素的下標
if nums[min_dix] > nums[j]:
min_dix = j
if i != min_dix:
# 交換當前元素和最小元素
nums[i], nums[min_dix] = nums[min_dix], nums[i]
return nums
print selectSort([1,2,0,4,9,8,5,4,7])
歸併排序
思想:
採用分治法,將兩個已經有序的序列合併成一個有序序列,得到完全有序的序列。即先使每個子序列有序,再使自序列之間有序。若將兩個有序表合併成一個有序表,成為2-路歸併。
步驟:
- 將長度為 n 的序列分成兩個長度為 n/2 的子序列
- 將這兩個自序列分別採用歸併排序
- 將兩個排序好的自序列合併成一個最終的排序序列
歸併排序最初的狀態,可以看成是 n 個長度為 1 的有序自序列。
在1個或2個元素時,1個元素不會交換,2個元素如果大小相等的話也不會交換,所以是穩定的
這個時候不是雙重迴圈,時間複雜度O(nlogn)
# -------- coding:utf-8 ------
'''
歸併排序
將兩個有序序列合併成一個有序序列,初始狀態是n個長度為1的有序序列
O(nlong), 穩定
'''
def mergeSort(nums):
# 先分解成n個長度為1的有序序列
if len(nums) <= 1:
return nums
mid_idx = len(nums) / 2
left_nums = mergeSort(nums[:mid_idx]) # 將左邊的部分資料進行排序
right_nums = mergeSort(nums[mid_idx:]) # 右邊的部分資料進行排序
return merge(left_nums, right_nums) # 將兩個有序陣列合併為一個有序書序
def merge(left_nums, right_nums):
result = []
left_idx, right_idx = 0, 0
# 逐個比較兩個陣列最前面的元素
while left_idx < len(left_nums) and right_idx < len(right_nums):
if left_nums[left_idx] < right_nums[right_idx]:
result.append(left_nums[left_idx])
left_idx += 1
else:
result.append(right_nums[right_idx])
right_idx += 1
# 將陣列剩下部分加入
result += left_nums[left_idx:]
result += right_nums[right_idx:]
return result
print mergeSort([1,2,0,9,4,5,8,7,3])
希爾排序
思想:
希爾排序又叫做縮小增量排序。是簡單插入排序的改進版,不同之處在於,它會優選比較距離較遠的元素。
步驟:
- 選擇增量序列:如 5 3 2 1
- 按增量序列個數 k,進行 k 趟排序,上面這個例子就是 4 趟排序
- 每趟排序,根據對應的增量,將器分成若干個長度為 m 的子序列,然後對各個子表進行直接插入排序
通常在實現的過程中,可以不用指定增量序列,初始增量 step = len(nums)/2,後面每一次 step/= 2.
def shellSort(nums):
n = len(nums)
step = n / 2
while step >= 1:
for i in range(step, n):
for j in range(i, 0, -step):
if nums[j] < nums[j - step]:
nums[j], nums[j - step] = nums[j - step], nums[j]
else:
break
step /= 2
return nums
因為相同的數在一次 step 中,可能不在同一個自序列,因此可能在這個過程中位置發生改變,所以希爾排序是不穩定的。
堆排序
思想:
堆排序是基於完全二叉樹,以大頂堆為例,大頂堆表示每個節點都大於或等於自己的孩子節點。
步驟:
- 將長度為 n 的待排陣列進行堆有序化構造成一個大頂堆
- 構造的過程是,假如有 n 個節點,則逐個檢查 n/2-1 ~ 0 這些節點,因為只有這些節點有孩子節點,如果他們比孩子節點小,則跟孩子節點進行交換 - 將大頂堆的根節點與尾節點進行交換
- 檢查剩下的 n-1 個節點
- 重複上面的步驟,直到大頂堆中只有一個節點
相關文章
- Python排序演算法之 選擇排序Python排序演算法
- python 常用的排序演算法Python排序演算法
- 經典排序演算法 — C#版本(中)排序演算法C#
- 演算法題:IP 地址和版本號排序演算法排序
- 【JavaScript快速排序演算法】不同版本原理分析JavaScript排序演算法
- Python進階-演算法-快速排序Python演算法排序
- Algorithm-sort 排序演算法 pythonGo排序演算法Python
- python實現氣泡排序、插入排序以及快速排序演算法Python排序演算法
- Python 一網打盡<排序演算法>之堆排序演算法中的樹Python排序演算法
- Python進階-演算法-插入排序Python演算法排序
- python實現希爾排序演算法Python排序演算法
- 10種python常見的排序演算法!Python排序演算法
- python實現常用五種排序演算法Python排序演算法
- 帶你掌握4種Python 排序演算法Python排序演算法
- 【JAVA演算法】排序演算法 -- 快速排序Java演算法排序
- 排序演算法__桶排序排序演算法
- 排序演算法__快速排序排序演算法
- 排序演算法__堆排序排序演算法
- 排序演算法:快速排序排序演算法
- 排序演算法 - 堆排序排序演算法
- 排序演算法-堆排序排序演算法
- 排序演算法 - 快速排序排序演算法
- Python語言的排序演算法有哪些?Python學習班!Python排序演算法
- Python十大演算法之氣泡排序Python演算法排序
- 排序演算法原理總結和Python實現排序演算法Python
- 演算法之常見排序演算法-氣泡排序、歸併排序、快速排序演算法排序
- 排序演算法--氣泡排序排序演算法
- 排序演算法:選擇排序排序演算法
- 排序演算法__氣泡排序排序演算法
- 排序演算法__選擇排序排序演算法
- 排序演算法__歸併排序排序演算法
- 排序演算法__計數排序排序演算法
- 排序演算法__希爾排序排序演算法
- 排序演算法__基數排序排序演算法
- 排序演算法–氣泡排序排序演算法
- 排序演算法:歸併排序排序演算法
- 排序演算法 - 歸併排序排序演算法
- 排序演算法(歸併排序)排序演算法