# 演算法與資料結構入門
本文所有內容與資料皆由本人蒐集與撰寫,轉載請註明出處。
本篇講義尚未完成。
![](https://hackmd.io/_uploads/Sy7FTNHea.png)
# 入門介紹
- [甚麼是演算法?](https://jason-chen-1992.weebly.com/home/-whats-algorithm)
- [甚麼是資料結構?](https://hackmd.io/@Aquamay/H1nxBOLcO/https%3A%2F%2Fhackmd.io%2F%40Aquamay%2Frk1C8ni5d)
來複習一下學習地圖,以臺大資工系必修為例:
![](https://i.imgur.com/Y2AdRO3.png =80%x)
以臺大資管系必修為例:
![](https://i.imgur.com/aC9lfrs.png =70%x)
# 競賽相關
適合國 / 高中生參加的相關競賽有以下:
- [Bebras 國際運算思維挑戰(簡單)](https://bebras.csie.ntnu.edu.tw/)
- [APCS(個人)](https://apcs.csie.ntnu.edu.tw/)
- [ISSC(團體)](https://issc.csroc.org.tw/)
- [TOI(資訊奧林匹亞,較難)](https://tpmso.org/toi/)
建議可以向學校老師或相關社團與補習班詢問更多細節。
### APCS Practice
- [應試相關資訊](https://apcs.csie.ntnu.edu.tw/index.php/info/)
- 建議每項都要讀過,特別是環境 / 作答系統 / 考場規則
#### 實作題
- [2024/01 APCS](https://zerojudge.tw/Problems?tag=2024%E5%B9%B41%E6%9C%88) and [Solution](https://hackmd.io/@bangyewu/SkKxG8Oua)
- [2023/10 APCS](https://zerojudge.tw/Problems?tag=2023%E5%B9%B410%E6%9C%88) and [Solution](https://hackmd.io/@bangyewu/SkxXo4QGa) or [Solution 2](https://dada878.com/blogs/apcs-2023-10-solution)
- [2023/06 APCS](https://zerojudge.tw/Problems?tag=2023%E5%B9%B46%E6%9C%88) and [Solution](https://hackmd.io/@bangyewu/B13lefwMp)
#### 觀念題
- [APCS 觀念題分析系列](https://hackmd.io/@howkii-studio/apcs_overview/https%3A%2F%2Fhackmd.io%2F%40howkii-studio%2Fapcs_exercise_cs)
- [APCS 觀念題資源分享](https://hackmd.io/@apcser/B1N5GYEto)
#### 相關資源
- 推薦:[AP325 - 從 APCS 實作題檢測三級到五級(C++)](https://drive.google.com/file/d/1hX7q3wVKkLuoMhEEm7uuLjq4BuhZAEgn/view?usp=drive_link)
- [AP325(Python)](https://hackmd.io/@bangyewu/Hy2kbYLI6/%2Fg2kqHh5_Q4eQnz-mfNu3Kw)
- [FB Group - APCS 實作題檢測](https://www.facebook.com/groups/359446638362710/)
- [PyAp45 Playlist - Python on APCS 四五級分](https://www.youtube.com/playlist?list=PLpmg1QLbgMuRQXHRkX9iDHyAVIW1D6OJF)
# 排序演算法(Sorting Algorithms)
![image](https://hackmd.io/_uploads/Hk0Xhj8x0.png)
排序演算法是一種將一組資料按照特定規則重新排列的方法。
常見的排序方法有:
- 選擇排序法(Selection Sort)
每次挑最大或最小的,依序移動到對應的位置。
- 插入排序法(Insertion Sort)
照順序每次拿一個,並插入正確的位置。
- 氣泡排序法(Bubble Sort)
就像有個氣泡,兩兩比對後留下大的,每次都把最大的帶到最後面。
- 合併排序法(Merge Sort)
將陣列不斷細分,再將細分後的結果兩兩合併。
- 快速排序法(Quick Sort)
選定一個 Pivot,將比他小的丟左邊比他大的丟右邊,再針對左右兩部分進行一次相同的事情。
練習:試著實作以上五種常見的 Sorting 方法吧!
> **推薦參考**:[介紹排序演算法的網站](http://notepad.yehyeh.net/Content/Algorithm/Sort/Sort.php)
> **推薦參考**:[寫程式的基本功:排序演算法](https://magiclen.org/sorting-algorithm/)
> 補充:[Python 中的 sorting](https://officeguide.cc/python-sort-sorted-tutorial-examples/)、[C++ 中的 sorting](https://shengyu7697.github.io/std-sort/)
> 補充:[最貼近現實的排序演算法 - Timsort](https://jason18153.medium.com/%E6%9C%80%E8%B2%BC%E8%BF%91%E7%8F%BE%E5%AF%A6%E7%9A%84%E6%8E%92%E5%BA%8F%E6%BC%94%E7%AE%97%E6%B3%95-timsort-a75da75b65a2)
補充:還有一些很奇怪的排序方法,看了會覺得很傻眼又好笑。如果有興趣可以參考 [10 Forbidden Sorting Algorithms](https://www.youtube.com/watch?v=ktgxMtWMflU) ,舉幾個例子像是:
- Bogo 排序法(Bogo Sort)
一直隨機重新排序,直到剛好符合大小順序。(猴子打字機定理)
- 史達林排序法(Stalin's Sort)
遇到大小順序不對的就直接刪掉。(所以最後的 list 有可能比原本的短)
# 搜尋演算法(Search Algorithms)
![image](https://hackmd.io/_uploads/HyNn3iIl0.png)
搜尋演算法是一種用來在資料集中尋找特定項目的方法或步驟。
## 適用於未排序或已排序的資料
### 線性搜尋(Linear Search)
直接一項一項搜尋,直到找到要的東西為止。
最基本的搜尋方式,時間複雜度為 $O(N)$。
## 僅適用於排序的資料
以下的搜尋演算法,會利用資料**已經排序過**的性質,來加速搜尋的過程。
### 二分搜尋(Binary Search)
很重要的搜尋演算法!將資料中間的與目標相比,若目標較大則往右再做一次搜尋,目標較小則往左,直到找到為止,可以參考 [二分搜尋法教學](https://magiclen.org/binary-search/) 與 [二分搜尋法的一些細節](https://medium.com/appworks-school/binary-search-%E9%82%A3%E4%BA%9B%E8%97%8F%E5%9C%A8%E7%B4%B0%E7%AF%80%E8%A3%A1%E7%9A%84%E9%AD%94%E9%AC%BC-%E4%B8%80-%E5%9F%BA%E7%A4%8E%E4%BB%8B%E7%B4%B9-dd2cd804aee1)。
#### Leetcode:
- [35. Search Insert Position](https://leetcode.com/problems/search-insert-position/)
- [69. Sqrt(x)](https://leetcode.com/problems/sqrtx/)
- [278. First Bad Version](https://leetcode.com/problems/first-bad-version)
### 指數搜尋(Exponential Search)
與二分搜尋類似,只是使用 2^N 作為搜尋的 index。
### 插補搜尋(Interpolation Search)
用線性插值的概念,來加速尋找的過程。
> **推薦參考**:[寫程式的基本功:搜尋演算法](https://magiclen.org/search-algorithm/)
# 時間複雜度(Time Complexity)
時間複雜度是衡量演算法執行效率的一個重要指標,表示隨著輸入規模增加,算法執行所需時間的增長速度。
常用的符號有:
- O-Notation:Big-O(Worst Case,最差)
- Θ-Notation:Big-Theta(Average Case,平均)
- Ω−Notation:Big-Omega(Best Case,最佳)
一般來說,我們最關心的是最差狀況下的時間複雜度(Big-O),關於詳細的數學推導可以參見補充。一些常見的時間複雜度與其例子為:
* $O(1)$:陣列讀取
* $O(n)$:簡易搜尋
* $O(log n)$:二分搜尋
* $O(nlogn)$:合併排序
* $O(n^2)$:選擇排序
* $O(2^n)$:費波那契數列
![](https://hackmd.io/_uploads/rk2-JzHlp.png)
我們來看看這些例子是如何被計算出來的:
- [初學者學演算法|從時間複雜度認識常見演算法](https://medium.com/appworks-school/%E5%88%9D%E5%AD%B8%E8%80%85%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-%E5%BE%9E%E6%99%82%E9%96%93%E8%A4%87%E9%9B%9C%E5%BA%A6%E8%AA%8D%E8%AD%98%E5%B8%B8%E8%A6%8B%E6%BC%94%E7%AE%97%E6%B3%95-%E4%B8%80-b46fece65ba5)
- [初學者學演算法|排序法進階:合併排序法](https://medium.com/appworks-school/%E5%88%9D%E5%AD%B8%E8%80%85%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-%E6%8E%92%E5%BA%8F%E6%B3%95%E9%80%B2%E9%9A%8E-%E5%90%88%E4%BD%B5%E6%8E%92%E5%BA%8F%E6%B3%95-6252651c6f7e)
- [初學者學演算法|從費氏數列認識何謂遞迴](https://medium.com/appworks-school/%E5%88%9D%E5%AD%B8%E8%80%85%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-%E5%BE%9E%E8%B2%BB%E6%B0%8F%E6%95%B8%E5%88%97%E8%AA%8D%E8%AD%98%E4%BD%95%E8%AC%82%E9%81%9E%E8%BF%B4-dea15d2808a3)
> 補充:[複雜度與漸進符號之數學](http://alrightchiu.github.io/SecondRound/complexityasymptotic-notationjian-jin-fu-hao.html)
> 補充:[時間複雜度與空間複雜度](https://jason-chen-1992.weebly.com/home/time-space-complexity)
# 資料結構(Data Structure)
資料結構是一種設計、組織、儲存資料的方式,以實現最佳性能和效率。這些結構包含不同形式,像是陣列、鍊結列表、樹、圖等等。選擇適當的資料結構對於解決特定的問題至關重要,不同的資料結構可以用於不同的應用,並且可以極大地影響程序的運行時間和記憶體使用。
相關參考:
- [C++ STL 容器(一) - 基本介紹](https://jasonblog.github.io/note/c++/stl_rong_qi_4e0029_-_ji_ben_jie_shao.html)
- [C++ API / STL 整理](https://hackmd.io/@meyr543/BkgMaiV6Y)
- [演算法與資料結構](https://alrightchiu.github.io/SecondRound/mu-lu-yan-suan-fa-yu-zi-liao-jie-gou.html)
## 陣列(Array)
![](https://hackmd.io/_uploads/SJJ_pSKMa.png)
可隨機存取的一串連續記憶體位址。
- [陣列 (Array) 簡介](https://notfalse.net/15/array-intro)
> 補充:[List Are Arrays in Python](https://michaeliscoding.com/lists-are-arrays-in-python/)
### Leetcode
- [26. Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)
- [27. Remove Element](https://leetcode.com/problems/remove-element/description/)
## 鏈結串列(Linked List)
![](https://hackmd.io/_uploads/HkbKTHFG6.png)
元素間彼此串聯在一起,形成一條鍊子的資料結構。
![image](https://hackmd.io/_uploads/SkxzAOjQp.png)
也可以是上圖雙向連結的形式。
- [Linked List:Intro(簡介)](https://alrightchiu.github.io/SecondRound/linked-list-introjian-jie.html)
- [Linked List:新增資料、刪除資料、反轉](https://alrightchiu.github.io/SecondRound/linked-list-xin-zeng-zi-liao-shan-chu-zi-liao-fan-zhuan.html)
### Leetcode
- [21. Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/)
- [24. Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/)
- [206. Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/)
## 堆疊(Stack, Last-In-First-Out, LIFO)
![](https://hackmd.io/_uploads/BkdcTSFMp.png)
單向進出,後進先出的資料結構,如同把東西堆疊起來。
- [Stack: Intro(簡介)](https://alrightchiu.github.io/SecondRound/stack-introjian-jie.html)
- [Stack: 以Array與Linked list實作](https://alrightchiu.github.io/SecondRound/stack-yi-arrayyu-linked-listshi-zuo.html)
- [Special Application: Min Stack](https://alrightchiu.github.io/SecondRound/stack-neng-gou-zai-o1qu-de-zui-xiao-zhi-de-minstack.html)
## 佇列(Queue, First-In-First-Out, FIFO)
![](https://hackmd.io/_uploads/H1tjpHFM6.png)
單向進出,先進先出的資料結構,如同在排隊一般。
- [Queue: Intro(簡介),並以Linked list實作](https://alrightchiu.github.io/SecondRound/queue-introjian-jie-bing-yi-linked-listshi-zuo.html)
- [Queue: 以Array實作Queue](https://alrightchiu.github.io/SecondRound/queue-yi-arrayshi-zuo-queue.html)
## Stack & Queue in Python: Collections.deque()
Deque(發音類似 Deck)為 Double-Ended Queue 的縮寫,顧名思義,Deque 是一個支援雙向存取的 Queue,也就是說,你可以從頭跟尾插入或移除元素。
- [官方說明文件](https://docs.python.org/zh-tw/3/library/collections.html#collections.deque)
```python=
from collections import deque
D = deque([1,2,3])
D.append(4)
D.appendleft(0)
print(D[2], D)
print(D.pop(), D)
print(D.popleft(), D)
```
```
Output:
2 deque([0,1,2,3,4])
4 deque([0,1,2,3])
0 deque([1,2,3])
```
Q:那他與 Stack 跟 Queue 有甚麼關係呢?
> A:
> Stack: 只使用 D.append() 與 D.pop() 的 deque
> Queue: 只使用 D.append() 與 D.popleft() 的 deque
>
> 其實只要符合 Stack 跟 Queue 的性質都可以。
> 因此以下使用方式也對,但較不建議使用:
> Stack: 只使用 D.appendleft() 與 D.popleft() 的 deque
> Queue: 只使用 D.appendleft() 與 D.pop() 的 deque
以下為使用 collections.deque 來實作 stack 與 queue 的例子:
```python=
from collections import deque
# For Stack, you can only use the following operations
S = deque()
# push from a stack:
S.append(val)
# pop from a stack:
val = S.pop()
# peek from a stack:
top = S[-1]
# check size of a stack:
size = len(S)
# check stack is empty:
isEmpty = (size == 0)
# =========================================
# For Queue, you can only use the following operations
Q = deque()
# push from a queue:
Q.append(val)
# pop from a queue:
val = Q.popleft()
# peek from a queue:
top = Q[0]
# check size of a queue:
size = len(Q)
# check queue is empty:
isEmpty = (size == 0)
```
另外也可以參考 Python 官方對 [將 List 作為 Stack / Queue 使用](https://docs.python.org/zh-tw/3/tutorial/datastructures.html#using-lists-as-stacks) 的說明。
介紹完 collections.deque() 以後,讓我們來實際練習一下 Leetcode 的題目吧!
### Leetcode
#### Stack
- [20. Valid Parentheses](https://leetcode.com/problems/valid-parentheses/)
- [155. Min Stack](https://leetcode.com/problems/min-stack/description/)
- [232. Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks/)
#### Queue
- [225. Implement Stack using Queues](https://leetcode.com/problems/implement-stack-using-queues/)
- [341. Flatten Nested List Iterator](https://leetcode.com/problems/flatten-nested-list-iterator/)
- [387. First Unique Character in a String](https://leetcode.com/problems/first-unique-character-in-a-string/)
## 樹(Tree)
![](https://hackmd.io/_uploads/S13npBFMp.png)
基本單位為 Node,且只有一個 Node 是 Root(無人指向的 Node),且不存在任何 Cycle。每個 Node 可以指向多個 Child。
- [Tree(樹): Intro(簡介)](https://alrightchiu.github.io/SecondRound/treeshu-introjian-jie.html)
### 二元樹(Binary Tree)
![image](https://hackmd.io/_uploads/SJQuAds7a.png)
當樹中的每個 Node 都只有兩個 Child,即為 Binary Tree。
- [Binary Tree: Intro(簡介)](https://alrightchiu.github.io/SecondRound/binary-tree-introjian-jie.html)
- [Binary Tree: Traversal(尋訪)](https://alrightchiu.github.io/SecondRound/binary-tree-traversalxun-fang.html)
以上面的 Binary Tree 為例:
- Pre-Order Traversal: ABDECFG
- In-Order Traversal: DBEAFCG
- Post-Order Traversal: DEBFGCA
![image](https://hackmd.io/_uploads/rJEw81ajp.png)
> 延伸閱讀:[Binary Tree: 建立一棵Binary Tree](https://alrightchiu.github.io/SecondRound/binary-tree-jian-li-yi-ke-binary-tree.html)
### 二元搜尋樹(Binary Search Tree)
![image](https://hackmd.io/_uploads/rJ5d1tom6.png)
若一個二元樹中,所有 Node 都滿足 Node.left.value < Node.value < Node.right.value,就稱為二元搜尋樹。二元搜尋樹有良好的排序特質,可以幫助我們找到想要的資料。
- [Binary Search Tree: Intro(簡介)](https://alrightchiu.github.io/SecondRound/binary-search-tree-introjian-jie.html)
- [Binary Search Tree: Search(搜尋資料)、Insert(新增資料)](https://alrightchiu.github.io/SecondRound/binary-search-tree-searchsou-xun-zi-liao-insertxin-zeng-zi-liao.html)
- [Binary Search Tree: Sort(排序)、Delete(刪除資料)](https://alrightchiu.github.io/SecondRound/binary-search-tree-sortpai-xu-deleteshan-chu-zi-liao.html)
> 注意:在 Binary Search Tree 上做 In-Order Traversal,即可得到排序好的資料!
### 進階 - 紅黑樹(Red Black Tree)
紅黑樹是一種進階的 BST(Binary Search Tree),透過將每個節點塗上紅色或黑色,並在新增或刪除資料時進行適當的結構調整(旋轉子樹),可以維持 BST 的高度不會相差太多,進而在搜尋時能有較好的效率。細節太過複雜這邊暫時跳過,之後有時間 or 有興趣再回來講。
![image](https://hackmd.io/_uploads/HyclMKj7p.png)
- [Red Black Tree: Intro(簡介)](https://alrightchiu.github.io/SecondRound/red-black-tree-introjian-jie.html)
> 延伸閱讀:
> - [Red Black Tree: Rotation(旋轉)](https://alrightchiu.github.io/SecondRound/red-black-tree-rotationxuan-zhuan.html)
> - [Red Black Tree: Insert(新增資料)與Fixup(修正)](https://alrightchiu.github.io/SecondRound/red-black-tree-insertxin-zeng-zi-liao-yu-fixupxiu-zheng.html)
> - [Red Black Tree: Delete(刪除資料)與Fixup(修正)](https://alrightchiu.github.io/SecondRound/red-black-tree-deleteshan-chu-zi-liao-yu-fixupxiu-zheng.html)
### 進階 - AVL 樹(AVL Tree)
![image](https://hackmd.io/_uploads/r1GAdTXt6.png)
AVL Tree 是一種 Binary search tree 實做方式,大部分的實做方式與 BST 一樣,差異在於 AVL tree 在過程中會透過計算並調整樹的結構來讓樹維持平衡,而不會導致 BST 過度傾斜(不平衡),與紅黑樹的目標類似。細節太過複雜這邊暫時跳過,之後有時間 or 有興趣再回來講。
> 延伸閱讀:[資料結構與演算法:AVL Tree](https://josephjsf2.github.io/data/structure/and/algorithm/2019/06/22/avl-tree.html)
### Leetcode
#### Basic - Traversal & Search
Please try to use both recursion and stack/queue to solve problem 102 and 144. (Hint: For 102(Level-Order) you should use **Queue**, for 144(Pre-Order) you should use **Stack**)
- [94. Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/description/)
- [102. Binary Tree Level Order Traversal](https://leetcode.com/problems/binary-tree-level-order-traversal/description/)
- [144. Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/description/)
- [145. Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/description/)
- [700. Search in A Binary Search Tree](https://leetcode.com/problems/search-in-a-binary-search-tree/description/)
#### Applications
- [100. Same Tree](https://leetcode.com/problems/same-tree/description/)
- [226. Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/description/)
- [530. Minimum Absolute Difference in BST](https://leetcode.com/problems/minimum-absolute-difference-in-bst/description/)
- [1026. Maximum Difference Between Node and Ancestor](https://leetcode.com/problems/maximum-difference-between-node-and-ancestor/description/)
- [1609. Even Odd Tree](https://leetcode.com/problems/even-odd-tree/description)
#### Tools
- [BT Visualizer](https://eniac00.github.io/btv/)
## 圖(Graph)
![](https://hackmd.io/_uploads/S1v-AHFM6.png)
圖比樹的限制更少,給定一群節點與相連的邊,即可稱為圖。邊可以分為有向與無向,節點之間的連結並沒有限制,也因此圖並不像樹有 root、parent、siblings、height 等等屬性,且有可能會有 cycle 的出現。
### Graph & Tree 的比較
![](https://hackmd.io/_uploads/HkvhyNtf6.png)
Tree 可以被看成一種特殊的 Graph,就像 Binary Tree 是一種特殊的 Tree 一樣。
### Graph 的表示法
![image](https://hackmd.io/_uploads/H1otPi8gA.png)
- [Graph: Intro(簡介)](https://alrightchiu.github.io/SecondRound/graph-introjian-jie.html)
### Graph 的搜尋
![image](https://hackmd.io/_uploads/r1Ef-7Pnp.png)
最常見、也最常使用的搜尋方法有兩種:BFS 與 DFS。兩者的差異在於搜尋的優先順序不同,並且分別可以使用 Queue 與 Stack 來實作。
#### 廣度優先搜尋(Breadth First Search, BFS)
- [Breadth First Search or BFS for a Graph](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/)
#### 深度優先搜尋(Depth First Search, DFS)
- [Depth First Search or DFS for a Graph](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/)
#### 那 DFS 與 BFS 可以應用在 Tree 上嗎?
因為 Tree 也是 Graph 的一種,所以當然可以,而且非常常用!
> 延伸閱讀:[DFS、BFS 與 Pre-Order、In-Order、Post-Order、Level-Order 的關係](https://stackoverflow.com/a/57598470/15894431)
### Leetcode
- [133. Clone Graph](https://leetcode.com/problems/clone-graph/description/)
- [797. All Paths From Source to Target](https://leetcode.com/problems/all-paths-from-source-to-target/description/)
- [841. Keys and Rooms](https://leetcode.com/problems/keys-and-rooms/)
- [997. Find the Town Judge](https://leetcode.com/problems/find-the-town-judge/description/)
---
#### 在圖中找環(Cycle)
上面的兩個例子中,都使用 `visited` 來紀錄該節點是否被拜訪過。因此,在**無向圖**中,若我們下一個要拜訪的節點的 `visited` 為 `True`,那我們就可以知道該圖中有環的存在。那在**有向圖**中呢?以下圖來說:
![image](https://hackmd.io/_uploads/rkSj6pq0a.png)
若我們在右邊的有向圖 b 中,用相同的 DFS 來尋找是否有環,假設第一次尋訪的路徑為 (1,2,4,5),而第二次尋訪退回到 2 並往下尋訪 (3,4),我們這時候會發現 `visited[4] == True`,並且判定該圖有環,但實際上是沒有的。那我們該怎麼做呢?
在往下看之前,先自己想想看喔!
答案:使用三個不同的值來表示每個節點不同的尋訪狀態(黑、白、灰)。黑色代表已經完成搜尋,白色代表還沒搜尋過,灰色代表正在這條 path 上搜尋,等搜尋完成後就會改為黑色。因此,若我們搜尋時遇到灰色節點,就可以知道該圖存在 cycle!
```python=
# Determine if a directed graph is acyclic
# True: Acyclic; False: Cyclic
graph = ... # adjacency list representation
N = len(graph)
visited = [0] * N
def dfs(node):
if visited[node] == -1: # gray, currently visiting
return False
elif visited[node] == 1: # black, done visiting
return True
else: # white, not visited yet (visited[node] == 0)
visited[node] = -1
for neighbor in graph[node]:
if not dfs(neighbor):
return False
visited[node] = 1
print(node)
return True
```
> 補充:[The purpose of grey node in graph depth-first search](https://cs.stackexchange.com/questions/9676/the-purpose-of-grey-node-in-graph-depth-first-search)
### 連通分量(Connected Components)
![image](https://hackmd.io/_uploads/r1EGVkc-A.png)
![ConnectedComponent4](https://hackmd.io/_uploads/BkStEJ9WR.png)
- [Connected Component - 演算法筆記](https://web.ntnu.edu.tw/~algo/ConnectedComponent.html)
- [Strongly Connected Components - Kosaraju 演算法](https://www.cnblogs.com/RioTian/p/14026585.html)
> 補充:[Connected Components in an Undirected Graph](https://www.geeksforgeeks.org/connected-components-in-an-undirected-graph/)
> 補充:[Strongly Connected Components](https://www.geeksforgeeks.org/strongly-connected-components/)
> 補充:[Tarjan 演算法與 Kosaraju 演算法](https://hackmd.io/@erichung0906/HkjZBH_IK)
### Leetcode
- [207. Course Schedule](https://leetcode.com/problems/course-schedule/description/)
- [1971. Find if Path Exists in Graph](https://leetcode.com/problems/find-if-path-exists-in-graph/description/)
> 延伸閱讀:
> - [Graph: Breadth-First Search(BFS,廣度優先搜尋)](https://alrightchiu.github.io/SecondRound/graph-breadth-first-searchbfsguang-du-you-xian-sou-xun.html)
> - [Graph: Depth-First Search(DFS,深度優先搜尋)](https://alrightchiu.github.io/SecondRound/graph-depth-first-searchdfsshen-du-you-xian-sou-xun.html)
> - [Graph: 利用DFS和BFS尋找Connected Component](https://alrightchiu.github.io/SecondRound/graph-li-yong-dfshe-bfsxun-zhao-connected-component.html)
> - [Graph: 利用DFS尋找Strongly Connected Component(SCC)](https://alrightchiu.github.io/SecondRound/graph-li-yong-dfsxun-zhao-strongly-connected-componentscc.html)
> - [Graph: 利用DFS尋找DAG的Topological Sort(拓撲排序)](https://alrightchiu.github.io/SecondRound/graph-li-yong-dfsxun-zhao-dagde-topological-sorttuo-pu-pai-xu.html)
## 矩陣(Matrix)
![image](https://hackmd.io/_uploads/SyxulaZA6.png)
在介紹 Graph 的表示方法時,我們提到了兩種不同的表示方式,分別是鄰接串列(Adjacency List)與鄰接矩陣(Adjacency Matrix)。不過其實,矩陣本身也可以被當作一種資料結構來使用,舉凡像是迷宮、地圖等等具有 2D 性質的資料型態,都可以使用矩陣來表示。
Matrix 的相關操作其實都與 Graph 差不多,不外乎就是在 Matrix 中進行搜尋或遍歷,但因為我們可以以 $O(1)$ 的複雜度,直接取用 Matrix 內部中的任一元素(`matrix[row][col]`),所以 Matrix 在某些應用上具有較為快速的優勢。那接著就讓我們直接實戰演練吧!
### Leetcode
- [200. Number of Islands](https://leetcode.com/problems/number-of-islands/description/)
- [733. Flood Fill](https://leetcode.com/problems/flood-fill/description/)
- [994. Rotting Oranges](https://leetcode.com/problems/rotting-oranges/description/)
- [1351. Count Negative Numbers in a Sorted Matrix](https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix/description/)
## 堆積(Heap)
![](https://hackmd.io/_uploads/BJqGCStzT.png)
### 堆積排序法(Heap Sort)
對陣列做 Heapify 變成 Max Heap,再不斷把最大值往後擺。
> 練習:試著實作 Heap Sort 吧!
## 優先佇列(Priority Queue)
![image](https://hackmd.io/_uploads/S1CWOylZ0.png)
- [Priority Queue:Intro(簡介)](https://alrightchiu.github.io/SecondRound/priority-queueintrojian-jie.html)
- [Priority Queue:Binary Heap](https://alrightchiu.github.io/SecondRound/priority-queuebinary-heap.html)
### Stack / Queue v.s. Priority Queue?
Stack 與 Queue 其實可以被視作特殊狀況的 Priority Queue:
- Stack:加入 Priority Queue 的 Priority 是嚴格遞增的
- 因此最後加入的元素 Priority 最高,會先被丟出 Stack
- Queue:加入 Priority Queue 的 Priority 是嚴格遞減的
- 因此最先加入的元素 Priority 最高,會先被丟出 Queue
<!-- In a stack, the priority of each inserted element is monotonically increasing; thus, the last element inserted is always the first retrieved. In a queue, the priority of each inserted element is monotonically decreasing; thus, the first element inserted is always the first retrieved. -->
### Priority Queue v.s. Heap?
- Priority Queue:一種**抽象資料類別**,著重的點是描述這個資料類別應該具有甚麼性質與操作方法,不直接討論實作方法。
- Heap:一種**資料結構**,著重的點在以特定的結構儲存資料。
因為他們具有類似的性質,所以用 Heap 的結構來實作 Priority Queue 這個資料類別,可以說是非常適合,也因此乍看之下他們好像是一樣的東西。但兩者概念上有些微不同,亦可以用其他方式來實做 Priority Queue。
> 補充:[Difference between priority queue and a heap](https://stackoverflow.com/a/18993313/15894431)
> 補充:[What's the difference between heapq and PriorityQueue in python?](https://stackoverflow.com/questions/36991716/whats-the-difference-between-heapq-and-priorityqueue-in-python)
## Heap / Priority Queue in Python: heapq
- [Python heapq](https://docs.python.org/zh-tw/3.10/library/heapq.html)
```python=
import heapq
k = 3
H = [1,3,5,7,9]
heapq.heapify(H)
heapq.heappush(H,2)
element = heapq.heappop(H)
element = heapq.heappushpop(H,2)
klargest = heapq.nlargest(k, H)
ksmallest = heapq.nsmallest(k, H)
```
### Leetcode
- [703. Kth Largest Element in a Stream](https://leetcode.com/problems/kth-largest-element-in-a-stream/description/)
- [1046. Last Stone Weight](https://leetcode.com/problems/last-stone-weight/description/)
- [1642. Furthest Building You Can Reach](https://leetcode.com/problems/furthest-building-you-can-reach/description/)
## 雜湊表(Hash Table)
![](https://hackmd.io/_uploads/r1cQCHKMa.png)
Application: Set, Dictionary...
### 集合操作(Set Operations)
![](https://hackmd.io/_uploads/HyidGe5Ma.png)
## 並查集(Disjoint Set / Union Find)
![image](https://hackmd.io/_uploads/ry305yeWA.png)
### Leetcode
- [547. Number of Provinces](https://leetcode.com/problems/number-of-provinces/description/)
# 其他常見的演算法(Algorithms)
演算法(Algorithm)是在有限的步驟之內,提供明確的法則,求出問題正確答案的程序。它可以是一種方法、法則或者程序,讓資料可按照預先設計的方式處理。
- [認識演算法](https://hackmd.io/@howkii-studio/Bkf-2DQiw/https%3A%2F%2Fhackmd.io%2F%40howkii-studio%2Falgorithm)
- 推薦補充閱讀:[演算法筆記](https://web.ntnu.edu.tw/~algo/)
## KMP Algorithm
## Backtracking
## Divide-and-Conquer
### Leetcode
- [108. Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/)
## Brute Force
## Greedy Method
## Dynamic Programming
- [演算法筆記:DP](https://web.ntnu.edu.tw/~algo/DynamicProgramming.html)
### Leetcode
- [62. Unique Paths](https://leetcode.com/problems/unique-paths/description/)
- [70. Climbing Stairs](https://leetcode.com/problems/climbing-stairs/description/)
## Graph 進階議題
### 最短路徑(Shortest Path)
- [Shortest Path:Intro(簡介)](https://alrightchiu.github.io/SecondRound/shortest-pathintrojian-jie.html)
### 戴克斯特拉演算法(Dijkstra's Algorithm)
- [基礎演算法系列 — Graph 資料結構與Dijkstra’s Algorithm](https://medium.com/%E6%8A%80%E8%A1%93%E7%AD%86%E8%A8%98/%E5%9F%BA%E7%A4%8E%E6%BC%94%E7%AE%97%E6%B3%95%E7%B3%BB%E5%88%97-graph-%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B%E8%88%87dijkstras-algorithm-6134f62c1fc2)
### Leetcode
- [743. Network Delay Time](https://leetcode.com/problems/network-delay-time/description/)
- [787. Cheapest Flights Within K Stops](https://leetcode.com/problems/cheapest-flights-within-k-stops/description/)
---
### 生成樹(Spanning Tree)
![image](https://hackmd.io/_uploads/S1zbFo8eC.png)
- [演算法筆記:Spanning Tree](https://web.ntnu.edu.tw/~algo/SpanningTree.html)
---
### 有向無環圖(Directed Acyclic Graph)與拓樸排序(Topological Sorting)
![image](https://hackmd.io/_uploads/B1txFj8gR.png)
- [演算法筆記:DAG](https://web.ntnu.edu.tw/~algo/DirectedAcyclicGraph.html)
### Leetcode
- [210. Course Schedule II](https://leetcode.com/problems/course-schedule-ii/description/)
# 附錄:Complexity Cheat Sheet
![](https://hackmd.io/_uploads/BkfMZStGp.png)
![](https://hackmd.io/_uploads/BJ50lHYGp.png)