現在如果想寫一個 Queue、Binary Search,甚至 Dijkstra,最簡單的方法可能已經不是打開課本,而是直接問 AI。
幾秒鐘後,我們就能得到一段看起來合理、甚至可以直接執行的程式碼。
那麼問題來了:
我們還需要學資料結構與演算法嗎?
我認為需要,只是到了 AI 時代,我們學它們的理由,已經不應該只是「面試會考」或「工程師應該具備的基礎」。
真正值得學的,是這些知識背後那套理解問題的方法。
假設今天我們想做一個導航功能。
如果直接告訴 AI:
幫我用 JavaScript 寫 Dijkstra Algorithm。
它大概很快就能完成。
但在這之前,其實還有更多問題需要先被回答:
這些問題都不屬於 Dijkstra 本身。
它們屬於更前面的步驟:
我們究竟如何理解眼前的問題?
如果連這一步都沒有想清楚,就算 AI 寫出的 Dijkstra 完全正確,也可能只是在非常精確地解一個錯誤的問題。
很多人第一次接觸資料結構,會看到:
然後開始記憶它們有哪些 API、時間複雜度是多少。
但我更想從另一個方向理解它們:
為什麼人們需要發明這些結構?
排隊時,我們在意的是先來先服務,所以有了 Queue。
返回時,我們總是先撤銷最後一步,所以 Stack 很自然。
檔案系統具有明確的上下階層,因此 Tree 很適合描述。
但捷運、道路、朋友關係與軟體依賴就不再是單純的上下層,它們更像一張 Graph。
資料結構其實是在回答:
我們應該用什麼方式描述資料之間的關係?
而不同的描述方式,又會直接影響後面可以使用哪些演算法。
同樣地,我也不希望這個系列最後變成:
今天背 BFS,明天背 DFS,後天背 Dijkstra。
因為演算法有趣的地方在過程:
為什麼這個問題需要這樣解?
例如 BFS 和 DFS 都可以走訪 Graph。
那為什麼找「最少經過幾站」時,我們通常想到 BFS?
為什麼道路加入不同距離後,BFS 又開始不夠用了?
為什麼 Greedy 有時候快又漂亮,有時候卻會得到錯誤答案?
為什麼有些問題明明知道最佳解存在,我們最後卻只使用 heuristic?
這些問題背後談的其實都是:
而這些才是真實世界裡,工程師真正需要處理的東西。
這 30 天不會以 LeetCode 題型作為主軸,也不打算完整涵蓋所有資料結構與演算法。
每一篇都會先從一個生活或工程問題開始。
例如:
接著再問:
這個問題背後真正的結構是什麼?
最後才引入對應的資料結構與演算法。
程式碼會有,但程式碼不是主角。
JavaScript 在這個系列裡比較像是一個實驗工具,幫我們把抽象概念實際跑一次。
整個系列大致會沿著五個階段前進:
先描述問題。
Queue、Stack、Hash Table、Tree、Graph。
再尋找答案。
Binary Search、DFS、BFS、Shortest Path。
答案很多時,開始做選擇。
Greedy、Knapsack、Scheduling、Matching。
當關係開始改變,問題也開始變複雜。
Dependency、Cycle、Propagation、Concurrency。
最後接受現實世界通常沒有完美答案。
Constraint、Heuristic、Approximation、Trade-off。
到了最後,我們還會把這套思考方式重新帶回軟體開發本身。
因為 State、Dependency、Reactive System,本質上也同樣需要回答:
資料之間到底存在什麼關係?
我並不認為 AI 讓學習資料結構與演算法這件事失去價值。
恰恰相反,當產生程式碼變得越來越便宜,我們需要負責的事情會更加清楚:
描述問題、設定條件、選擇模型,以及判斷答案是否合理。
AI 可以幫我們解釋概念,也可以協助實作。
但如果我們自己不知道:
那麼我們也很難判斷 AI 給出的答案究竟好不好。
所以這 30 天,我想重新從生活出發認識一次資料結構與演算法。
去探討一件我認為更重要的事情:
如何把一個模糊的現實問題,轉換成我們可以理解、推理,並做出選擇的模型。
下一篇,我們就從最基本的問題開始:
如果所有資料都可以放進 Array,為什麼還需要資料結構?