已發布·持續改進
Algorithm
排序演算法將資料依序排列。本主題涵蓋合併排序、快速排序、堆積排序、穩定性、n log n 下界、計數排序與各語言的內建排序。
排序是把元素依數值、字母或時間等既定順序重新排列的演算法。它大致分為兩類:比較排序(泡沫排序、插入排序、選擇排序、合併排序、快速排序、堆積排序)只透過比較兩個元素來決定先後;非比較排序(如計數排序和基數排序)則直接利用整數的值或各位數字。
排序是二分搜尋、去除重複、區間合併、排名等大量工作的前置步驟,因此是最先學習的基礎演算法之一。了解比較排序在最壞情況下至少需要 Ω(n log n) 次比較這個下界、穩定排序與原地排序的差別,以及 Python 的 Timsort、多數 C++ std::sort 實作採用的內省排序等內建排序的行為,能幫助你在實務開發和技術面試中做出正確選擇。
學習時,建議先在小陣列上手動追蹤插入排序、合併排序和快速排序的過程,再親自實作合併排序和快速排序,並比較它們的最佳、平均和最壞複雜度。之後練習用 key 函式和比較器呼叫內建排序,並解決區間合併、逆序對計數等以排序為基礎的問題。
合併排序把輸入一分為二再合併,快速排序則圍繞基準值進行分割。兩者的平均時間複雜度都是 O(n log n)。
穩定排序會保持相等鍵元素的原始順序,原地排序幾乎不佔用額外記憶體。哪一點更重要取決於實際需求。
決策樹論證顯示,任何比較排序在最壞情況下都需要 n log n 數量級的比較次數。合併排序和堆積排序達到了這個下界。
計數排序和基數排序不比較元素,能在接近線性的時間內對值域或位數有限的整數排序。
merge_sort 把串列一分為二,分別遞迴排序,然後每次取兩個已排序串列開頭較小的元素,把它們合併成一個串列。相等時先取左邊的元素(<=),因此是穩定排序,而且對任何輸入都是 O(n log n)。最後一行檢查結果是否與內建的 sorted() 一致。
merge_sort.py
def merge_sort(items):
"""Return a new sorted list (stable, O(n log n))."""
if len(items) <= 1:
return list(items)
mid = len(items) // 2
left, right = merge_sort(items[:mid]), merge_sort(items[mid:])
merged, i, j = [], 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]: # take the left one on ties: stable
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
return merged + left[i:] + right[j:]
if __name__ == "__main__":
data = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(data)) # [3, 9, 10, 27, 38, 43, 82]
print(merge_sort(data) == sorted(data)) # True
python merge_sort.py共六章,帶你從安裝一步步認識 排序 的核心概念。
在這裡提問、分享經驗,交流關於 排序 的看法。
還沒有討論。來發起第一則吧。
0 則留言
登入 · 登入後即可留言。
來留下第一則留言吧。