1.希爾排序
在上一篇,我們講了插入排序, 也是一種基於比較的排序。其實還有一個大佬提出一種改進的插入排序:希爾排序(shell sort)。
希爾排序的思想是:
先對序列進行分組,每次尋求一個gap:例如:
2 1 3 5 9 1 6 8
length = 8
gap = length / 2 = 4
就分成4組: 然後對每一組進行插入排序。
例如:
2 1 3 5 9 1 6 8
然後對每一組進行插入排序:
2 9 --- 插入排序
1 1 --- 插入排序
3 6 --- 插入排序
5 8 --- 插入排序
2 1 3 5 9 1 6 8
雖然每一組字面上來說,根本不需要排序。
接着,gap = gap / 2,如此繼續執行上述操作。
這樣做,可以減少插入排序的次數。
算法複雜度和穩定性:
希爾排序的時間複雜度是: 最好情況: 最壞情況: 不需要佔用多餘的空間,空間複雜度O(1);是不穩定排序。
python版本的實現:
def shell_sort(self, list):
"""
希爾排序,希爾排序基於插入排序,不過是先對序列進行分組
然後對分組執行插入排序
:return: 插入排序的結果
"""
n = len(list)
gap = n // 2
while gap >= 1:
## 插入排序
for i in range(0, n - gap):
## 讓間隔gap的元素爲一組
j = i + gap
while j > 0:
if list[j] < list[j - gap]:
(list[j - gap], list[j]) = (list[j], list[j - gap])
j -= gap
else:
break
## gap折半,直至1
gap = gap // 2
## 返回結果
return list
2. 快速排序
快速排序的思想是一種基於分治的思想:
先找一個樞點,把序列分成兩部分,一部分全都不小於該樞點,一部分全都大於該樞點。
然後對這兩部分再進行快排
。
這個過程中,就採用了分而治之思想,化複雜爲簡單。
快排的時間複雜度是: 他的排序過程,就不再演示了。這裏直接給出算法複雜度分析:
算法複雜度和穩定性:
希爾排序的時間複雜度是 最好情況, 最壞情況: 不需要佔用多餘的空間,空間複雜度O(1);是不穩定排序。
python版本的代碼實現:
def quick_sort(self, list, first, end):
"""
快速排序 基於分治的思想,找到一個值,把比這個元素小的,分成左邊部分;
把比這個元素大的,分成右邊部分。
接着對左邊部分和右邊部分,分別進行快速排序
:param list:
:param first:
:param end:
:return:
"""
low = first
high = end
pivot = list[low]
if low >= high:
return
while low < high:
while low < high and list[high] >= pivot:
high -= 1
list[low] = list[high]
while low < high and list[low] < pivot:
low += 1
list[high] = list[low]
## 此時,low == high, 把elment放在low指向的元素
list[low] = pivot
print(list)
self.quick_sort(list, first, low - 1)
self.quick_sort(list, low + 1, end)
3.歸併排序
歸併排序的思想是:先拆分序列,直到不能拆分的單個元素;然後把每個元素當作一個序列,他們分別都是有序的。那麼兩兩合併,非常容易,因爲是有序序列:
例如:5 8 1 2,拆分成4個數組: [5], [8] ,[1], [2]。接着兩兩合併成:
[5 8]
[1 2]
接着,就複雜一點,兩個索引:up, down,分別指向 5, 1:
up
|
5 8
down
|
1 2
合併結果: 【1】
down
|
5 8
up
|
2
結果: 【1,2】
把剩餘5和8放入數組,結果:【1,2,5,8】
算法複雜度和穩定性:
希爾排序的平均時間複雜度是 最好情況, 最壞情況: 需要佔用最多長度爲n的空間,空間複雜度
希爾排序是穩定排序。
python版本的代碼實現:
def merge_sort(self, list):
"""
歸併排序的實現
:param self:
:param list:
:return:
"""
n = len(list)
if n == 1:
return list
mid = n // 2
print("mid:", mid)
left = self.merge_sort(list[:mid])
right = self.merge_sort(list[mid:])
print("left list:", left)
print("right list:", right)
result = self.merge(left, right)
return result
def merge(self, left_list, right_list):
"""
合併兩個列表
:param right_list:
:return:
"""
list = []
left = 0
right = 0
left_len = len(left_list)
right_len = len(right_list)
print("merge, left len:", left_len, "right_len:", right_len)
while left < left_len and right < right_len:
if left_list[left] < right_list[right]:
list.append(left_list[left])
left += 1
else:
list.append(right_list[right])
right += 1
## 把剩餘的元素移動到list中
if left < left_len:
while left < left_len:
list.append(left_list[left])
left += 1
if right < right_len:
while right < right_len:
list.append(right_list[right])
right += 1
return list
總結
各種算法的分析和總結:
排序算法 | 平均情況 | 最好情況 | 最壞情況 | 輔助空間 | 穩定性 |
---|---|---|---|---|---|
冒泡排序 | O(n) | O(1) | 穩定 | ||
選擇排序 | O(1) | 不穩定 | |||
插入排序 | O(n) | O(1) | 穩定 | ||
希爾排序 | O(nlogn) ~ | O(1) | 不穩定 | ||
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 穩定 |
歸併排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 穩定 |
快速排序 | O(nlogn) | O(nlogn) | O(nlogn) ~ O(n) | 不穩定 |