# 基礎排序 2020竹C, jeeeerrrpop --- ## 生活中的例子 - 一堆散落的紙有頁碼,我們想把它重新排成一本書。 - 要把學生的成績由大到小排序。 - ........ --- {%youtube WaNLJf8xzC4%} --- 給你一個長度為n的序列 你要把他們由小到大排序 --- ## Swap 先介紹基於比較、交換的演算法。 ```python= a, b = b, a ``` --- 何謂演算法? 我們能自己想到排序演算法嗎? --- ## Bubble Sort - 從序列的最前面開始,一次比較陣列中兩兩相鄰的元素,然後根據將大的移到後面。 - 當我們比較過所有元素一次後,可以確保數值最大的元素在最後面。 - 接著扣掉陣列中的最後一個元素,接著重複上面的步驟進行兩兩比較。 --- ## Bubble Sort ```cpp void BubbleSort(int arr[], int n) { for(int i = 0; i < n - 1; i++) { for(int j = 0; j < n - i - 1; j++) { if(arr[j] > arr[j + 1]) swap(arr[j], arr[j + 1]); } } } ``` --- ## Selection Sort - 在序列中找到最小的元素,並將他與第一個元素交換。 - 在序列中找到第二小的元素(也就是撇除掉第一個元素後的最小的元素),並將他與第二個交換。 - 重複以上操作,直到排序好。 --- ## Selection Sort ```cpp void SelectionSort(int arr[], int n) { for(int i = 0; i < n - 1; i++) { int min = i; for(int j = i + 1; j < n; j++) { if(arr[j] < arr[min]) min = j; } swap(arr[i], arr[min]); } } ``` --- ## Insertion Sort - 想像序列中有一部分是已經排序好的,那每次新增一個元素就去看他要插在排序好的序列的哪裡。 - 對於陣列中第 i 個值,假設 0 ~ i - 1 都排序好了,把 i 往左比較找到第一個小於他的元素並插在他右邊。 --- ## Insertion Sort ```cpp void InsertionSort(int arr[], int n) { for(int i = 1; i < n; i++) { int j = i - 1; while (j >= 0 && arr[j] > arr[j + 1]) { swap(arr[j], arr[j + 1]); j--; } } } ``` --- ## Quick Sort [Quick Sort](http://alrightchiu.github.io/SecondRound/comparison-sort-quick-sortkuai-su-pai-xu-fa.html) --- ## Merge Sort [Merge Sort](http://alrightchiu.github.io/SecondRound/comparison-sort-merge-sorthe-bing-pai-xu-fa.html) --- ## 複雜度分析 - Bubble Sort - Best: $O(n^2)$, Worst $O(n^2)$ - Selection Sort - Best: $O(n^2)$, Worst $O(n^2)$ - Insertion Sort - Best: $O(n)$, Worst $O(n^2)$ - Quick Sort - Worst $O(n^2)$, Average $O(nlogn)$ - Merge Sort - $O(nlogn)$ --- Bubble Sort 若在迴圈執行時,判斷這一輪是否都沒有任何元素交換,可以把最優情況下的複雜度降低到 $O(n)$。 Insertion Sort 若把內層迴圈改成二分搜,就可以優化成 $O(nlogn)$。 --- 有複雜度比 $O(nlogn)$ 更好的排序方法嗎? --- 基於比較的排序演算法最好就是 $O(nlogn)$ [優質文章](https://tmt514.github.io/algorithm-analysis/sorting/comparison-based-sorting.html#定理-18) --- ## 不基於比較的排序方法 - Counting Sort - Bucket sort - radix sort --- ## Counting Sort - 假如數值介於 0 ~ 999,我們就開一個長度為1000的陣列去記每一種數字出現幾次。 - 最後由小到大輸出 --- ## Counting Sort ```cpp const int size = 1000; void CountingSort(int arr[], int n) { int cnt[size] = {0}; for(int i = 0; i < n; i++) { cnt[arr[i]]++; } int id = 0; for(int i = 0; i < size; i++) { while(cnt[i] > 0) { arr[id] = i; id++; cnt[i]--; } } } ``` --- ## Counting Sort 時間複雜度是 $O(n)$ 嗎? --- ## Counting Sort k 為數字範圍 時間複雜度 $O(n + k)$ --- ## 上課練習 [neoj 369](https://neoj.sprout.tw/problem/369/) --- 既然都有 $O(nlogn)$ 的排序演算法了,那些$O(n^2)$的演算法根本不會被用到吧? --- 當序列長度不大的時候,Insertion Sort等等反而會比Quick Sort, Merge Sort還來得有效率。 [reference](http://alrightchiu.github.io/SecondRound/comparison-sort-insertion-sortcha-ru-pai-xu-fa.html) --- 我不想自己寫SortQQ [std::sort](http://www.cplusplus.com/reference/algorithm/sort/) --- ```cpp #include <algorithm> int a[1000]; std::sort(a, a + 5); ``` --- 酷酷的影片 {%youtube kPRA0W1kECg%} --- Homework [neoj 2219](https://neoj.sprout.tw/problem/2219/)
{"metaMigratedAt":"2023-06-15T07:55:13.133Z","metaMigratedFrom":"Content","title":"基礎排序","breaks":true,"contributors":"[{\"id\":\"7692497a-be9a-4cb4-81b9-afb37e7453a8\",\"add\":3927,\"del\":657}]"}
    448 views