or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing
xxxxxxxxxx
Algorithm 演算法排序筆記
此筆記的原始碼
時間複雜度(Time complexity) \(O(f(n))\)
定義\(T(n)\)表示程式執行所要花費的時間,\(n\)代表資料輸入量。
\(O(f(n))\)可被視為某演算法在電腦執行所需時間不會超過某一常數倍的\(f(n)\),也就是說當某演算法所需的執行時間為\(T(n)\),那其時間複雜度為\(O(f(n))\)。
以數學式表示:
\({\exists}c,n_0{\in}constant\),
if \(n{\geq}n_0\), then \(T(n){\leq}c\cdot f(n)\)
所估出來的函數式真正所需執行的上限。
常見的Big-O有下列幾種:
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →排序演算法
氣泡排序法(Bubble Sort)
從第一個元素開始,比較相鄰元素大小,如果順序有誤,則對調再進行下一個元素的比較。掃描過一次後就可以確保最後一個元素是位於正確的位置。接著再進行第二次掃描,直到所有元素完成排序為止。
時間複雜度:
當資料的順序恰好由小到大時,第一次掃描後,沒有進行任何swap \(\Rightarrow\) 提前結束
當資料的順序恰好為由大到小時,每回合分別執行:\(n-1、n-2、...、1\)次 因此\((n-1)+(n-2)+...+1=n\cdot\frac{(n-1)}{2}\) \(\Rightarrow\) \(O(n^2)\)
每個數字要執行的次數為\(0、1、2、3、...、n-1\),因此每個數字平均的執行次數是\(\frac{0+1+2+3+...+(n-1)}{n}=\frac{(n-1)}{2}\),有\(n\)個數字,所以所需平均時間為\(n\cdot\frac{(n-1)}{2}=\frac{(n^2-n)}{2}\) \(\Rightarrow\) \(O(n^2)\)
空間複雜度:
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/bubblesort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/bubblesort.c
改良Bubble Sort (Modified Bubble Sort)
Bubble Sort的時間複雜度只有在給定的陣列為從小到大排序好的情形才會是\(O(n)\),其餘情況階是維持\(O(n^2)\)。因此我們使用一個flag變數去停止bubble sort當陣列已經被排序好了。 初始化flag為True,當有元素進行交換時,flag改為False,當進行完整個迴圈後,若flag還是維持True,則表示該陣列已經被排序好了,便可以停止bubble sort了。
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/bubblesort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/bubblesort.c
選擇排序法(Selection Sort)
將資料分成已排序及未排序兩部分,依序在未排序中找最小值,加入到已排序部分的末端。按照這個方式,可以在第一輪中找到最小的,第二輪找到第二小的。那要如何從未排序的數列中找到最小值呢?可以先設未排序陣列的第一個數字是目前的最小值,然後再往後一個一個比大小,如果後面的數字比目前的最小值小,那就將目前的最小值換為這個數。
時間複雜度:
分成兩個步驟討論:
在n個未排序數列中找到最小值需要\(n\)個步驟,因此對於selection sort而言,第一回合要從\(n\)個未排序數列中找到最小值需要\(n\)個步驟,第二回合要從\(n-1\)個未排序數列中找到最小值需要\(n-1\)個步驟,一直到最後一個回合需要一個步驟為止。因此總步驟數為\((n+(n-1)+(n-2)+...+1)=\frac{n\cdot(n+1)}{2}\)。
每次找到最小的數值,將其與未排序好的第一個數字交換位置,每一個回合需要一個步驟,總共執行\(n\)個回合,需要\(n\)個步驟。
因此selection sort共需要\(\frac{n\cdot(n+1)}{2}+n=\frac{n\cdot(n+3)}{2}\) \(\Rightarrow\) \(O(n^2)\)
空間複雜度:
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/selection_sort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/selectionsort.c
插入排序法(Insertion Sort)
想像手上又一副撲克牌,想要將其由小到大排序。可以將第\(i\)張牌加入前\(i-1\)張以排序過的牌,那就可以獲得\(i\)張排序過的牌組了。
時間複雜度:
當處理的資料為\(1、2、3、4、...、N\)時,僅需比較\(N\)次便可以完成排序。另一方面也表示,當給定的數列已經接近排序的狀態時,用insertion sort效率會很高。
當處理的資料為顛倒的順序:\(N、N-1、N-2、...、2、1\)時,那麼位在第\(i\)個的數字將會需要比較\(i-1\)次,因此總步驟數為\(0+1+2+...+(N-1)=\frac{n\cdot(n-1)}{2}\) \(\Rightarrow O(n^2)\)
這個好難,之後再來搞懂他,如連結
空間複雜度:
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/insertion_sort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/insertionsort.c
說明:以\(array=[5,2,4,6,1,3]\)為例。
希爾排序法(Shell Sort)
為進化版的插入排序法,改良insertion sort中每次只能將資料移動一位的缺點,因此能夠使原本距離較遠的數字快速歸位。添加了間距(gap)的觀念,往左邊間距gap的數字比大小,可讓在陣列後端數值較小的數字較快回到陣列前端。
舉例說明:有\(15\)筆資料,取\(gap\)分別為\(5、2、1\)
第一回合: \(gap=5\)
對\(index\)為\(0、5、10\)做insertion sort
Example:
排序後:
對\(index\)為\(1、6、11\)做insertion sort
對\(index\)為\(2、7、12\)做insertion sort
對\(index\)為\(3、8、13\)做insertion sort
對\(index\)為\(4、9、14\)做insertion sort
經過上面\(gap=5\)的insertion sort後可以發現顏色相同的數組已經按照順序排好了。
第二回合: \(gap=2\)
可以看出顏色相同的數組已經被由小到大排序好了,此外,也可以看到較小的數字已經都在左側,而較大的數字也都已經移到右側了,已經變成一個快要完全排序完成的數列了,此時我們可以進行\(gap=1\)的排序,其實也就是前面所介紹的insertion sort,在這種快要排序好的數列中,insertion sort的效能會是很高的。
第三回合: \(gap=1\),其實就是前面所說的insertion sort,只不過這邊不分組,是將所有數列一起做一次insertion sort,便可以得到最終排序好的數列。
好懂的示意影片:
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →時間複雜度:
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/shell_sort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/shellsort.c
合併排序法(Merge Sort)
分治法(Divide-and-conquer):
在進入合併排序法前,我們先來看看分治法:把一個複雜的問題分成兩個或更多的相同或相似的子問題,直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。
在紙房子(一)第11集中,教授有預期警方會透過這種分治法去一一擊破夥伴們的心理,因此有事先想好應對的策略!
合併排序法大致上可以分為切分與排序
舉例說明:
時間複雜度:
空間複雜度:
python code(divide and conquer):
code:https://github.com/coherent17/algorithm/blob/main/sorting/merge_sort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/mergesort.c
快速排序法(Quick Sort)
找到一個基準點(pivot),將比這個基準點小的元素放至左邊的子陣列,將比這個基準點大的元素放到右邊的子陣列,如此一來便能確定這個基準點的位置會是最終排序過後正確的位置,再對左邊的子陣列與右邊的子陣列重複進行相同的步驟,便能完成排序。
舉例說明:
Note:此處pivot的選擇為要排序陣列的最後一個元素
\(i\)要找的是比pivot大的元素,而\(j\)要找的是比pivot小的元素。
\(i\)往右移,直到找到比pivot數值還要大的元素便停止:
\(j\)往左移,直到找到比pivot數值還要小的元素便停止:
而後將陣列中\(index\)為\(i\)與\(j\)的元素對調:
持續進行上面的步驟直到\(i < j\):
(\(i\)往右移找比pivot大的,\(j\)往左移找比pivot小的)
而後將陣列中\(index\)為\(i\)與\(p\)的元素對調:
此時已經可以確定最開始時設定的pivot位置對於最終排序好的陣列是不會再改變了,而且在pivot左邊的子陣列中的元素都比它小,而pivot右邊的子陣列中的元素都比它大。未來僅需對pivot左邊的子陣列及右邊的子陣列同樣進行上述的步驟,便可以得到排序好的陣列!
對於左邊的子陣列持續進行上面同樣的步驟直到\(i < j\):
(\(i\)往右移找比pivot大的,\(j\)往左移找比pivot小的)
而後將陣列中\(index\)為\(i\)與\(p\)的元素對調: (剛好是同一個元素,位置不動)
繼續對左邊的子陣列進行一樣的步驟:
此時可以發現\(i\)與\(j\)為同一個元素,直接判斷此元素是否比pivot大,若有將陣列中\(index\)為\(i\)與\(p\)的元素對調,若否,則維持不動。
我們就完成左半邊陣列的排序了,接著對陣列右半邊以同樣的步驟進行排序,最後變可以成功地得到已排序的陣列:
時間複雜度:
python code(divide and conquer):
code:https://github.com/coherent17/algorithm/blob/main/sorting/quicksort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/quicksort.c
基數排序法(Radix Sort)
為一種分配式的排序法(distribution sort),可以分成LSD或MSD,在不同的情形可以使用不同的方式,使其達到最高效率。在做基數排序法的時候會用到桶子,存放陣列的值。
舉例說明:
以LSD(least significant digit)為例子:
給定義下陣列:
Step 1:
在經過這些數值時,依據個位數的大小將其分配到0~9的桶子內,並遵守下面的規則:
按照以上規則,將陣列的所有數值依據個位數排序好之後可以獲得:
Step 2:
將剛剛依據個位數放進桶子的數值串接起來,並遵守下面的規則:
由以上規則,我們所得到的陣列為:
Step 3:
重複Step 1,不過改成對十位數進行分配:
按照以上規則,將陣列的所有數值依據十位數排序好之後可以獲得:
Step 4:
重複Step 2,將其串接在一起,便完成了排序:
要進行幾次的分配及串接是取決於這些數值中最大位數的那個數字有幾位。
LSD的radix sort適用於位數較少的數列,然而在運算數值較大的陣列則是MSD的radix sort效率會比較高。
時間複雜度:
定義\(n\)為陣列長度,而\(k\)為此陣列最大數字的位數。
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/radixort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/radixsort.c
推積排序法(Heap Sort)
在了解堆積排序法前,需要先知道:
complete binary tree(完全二元樹):
heap data structure(堆積):
example:
example:
C code for max heap data structure:
code:https://github.com/coherent17/algorithm/blob/main/sorting/max_heap_data_structure.c
Heap sort實踐方法:
那要如何透過堆積的排序數列呢?我們可以將每次heapify後的binary tree的最大值(根部root),將其與樹的末端交換,也就是將其放到陣列的最後一個位置,之後刪除其在binary tree中的位置,再繼續進行相同的動作便可以將此數列排序完畢。
時間複雜度:
python code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/heapsort.py
C code:
code:https://github.com/coherent17/algorithm/blob/main/sorting/heapsort.c