很多有用的演算法結構上是遞迴的,為了解決乙個特定問題,演算法一次或者多次遞迴呼叫其自身以解決若干子問題。 這些演算法典型地遵循分治法的思想:將原問題分解為幾個規模較小但是類似於原問題的子問題,遞迴求解這些子問題, 然後再合併這些問題的解來建立原問題的解。
分治法在每層遞迴時有三個步驟:
現在我們就來看下歸併排序是是如何利用分治法解決問題的。
考慮我們排序這個陣列:[10,23,51,18,4,31,13,5] ,我們遞迴地將陣列進行分解
當陣列被完全分隔成只有單個元素的陣列時,我們需要把它們合併回去,每次兩兩合併成乙個有序的序列。
用遞迴**來描述這個問題:
def merge_sort(seq):
if len(seq) <= 1: # 只有乙個元素是遞迴出口
return seq
else:
mid = int(len(seq)/2)
left_half = merge_sort(seq[:mid])
right_half = merge_sort(seq[mid:])
# 合併兩個有序的陣列
new_seq = merge_sorted_list(left_half, right_half)
return new_seq
注意我們這裡有乙個函式沒實現,就是如何合併兩個有序陣列 merge_sorted_list。其實你在紙上畫一畫, 合併兩個有序陣列並不難實現。
""" 合併兩個有序序列,返回乙個新的有序序列
:param sorted_a:
:param sorted_b:
"""length_a, length_b = len(sorted_a), len(sorted_b)
a = b = 0
new_sorted_seq = list()
while a < length_a and b < length_b:
if sorted_a[a] < sorted_b[b]:
a += 1
else:
b += 1
# 最後別忘記把多餘的都放到有序陣列裡
if a < length_a:
new_sorted_seq.extend(sorted_a[a:])
else:
new_sorted_seq.extend(sorted_b[b:])
return new_sorted_seq
這樣就實現了歸併排序,並且你會發現它返回乙個新的陣列而不是修改原有陣列。
我們來簡單看下它歸併排序的時間複雜度,假設排序 n 個數字時間複雜度是 t(n),這裡為了方便假設 n 是 2 的冪
總的代價是 cnlg(n)+cncnlg(n)+cn ,忽略常數項可以認為是 o(nlg(n))。如果這個圖看不懂,我們自己求解下也不難,首先我們簡化一下, 把常數係數當成 1,得到以下遞迴式:
希爾排序法基本思想
希爾排序 shell sort 又稱為 縮小增量排序 是1959年由d.l.shell提出來的。該方法的基本思想是 先將整個待排元素序列分割成若干個子串行 由相隔某個 增量 的元素組成的 分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序 增量足夠小 時,再對全體元素進行一...
氣泡排序演算法的基本思想
1 氣泡排序的基本思想 氣泡排序是交換排序中一種簡單的排序方法。它的基本思想是對所有相鄰記錄的關鍵字值進行比效,如果是逆順 a j a j 1 則將其交換,最終達到有 序化 其處理過程為 1 將整個待排序的記錄序列劃分成有序區和無序區,初始狀態有序區為空,無序區包括所有待排序的記 錄。2 對無序區從...
氣泡排序的基本思想
1 氣泡排序的基本思想 氣泡排序是交換排序中一種簡單的排序方法。它的基本思想是對所有相鄰記錄的關鍵字值進行比效,如果是逆順 a j a j 1 則將其交換,最終達到有序化 其處理過程為 1 將整個待排序的記錄序列劃分成有序區和無序區,初始狀態有序區為空,無序區包括所有待排序的記錄。2 對無序區從前向...