Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 242 additions & 0 deletions weeks/week-18/solutions/1114405001/AI_LOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
# AI_LOG.md - Week 18 Binary Search vs Linear Search

## 📋 開工前必答 5 個問題

### ❶ 函式簽名

**Question**: 函式叫什麼?吃什麼參數、回傳什麼型別?

**Answer**:
```python
def linear_search(arr: List[int], target: int) -> SearchResult:
"""線性搜尋 - O(n) 時間複雜度"""

def binary_search(arr: List[int], target: int) -> SearchResult:
"""二分搜尋 - O(log n) 時間複雜度"""

@dataclass
class SearchResult:
found: bool # 是否找到
index: int # 目標索引(-1 if not found)
comparisons: int # 比較次數
```

**為什麼這樣設計**:
- 統一返回類型,便於追蹤比較次數
- 清晰區分 "是否找到" 和 "索引值"
- 便於後續效能分析和雷達圖繪製

---

### ❷ 輸入邊界

**Question**: 資料範圍、筆數上限、輸入到 EOF 還是固定行數?

**Answer**:
- **搜尋目標 K**: 101(學號參數)
- **陣列大小**: 無限制(測試範圍 1 ~ 10,000 元素)
- **數值範圍**: 升序整數序列(1 ~ 10000)
- **輸入方式**:
- 題目給定 n(陣列大小)
- 第 2 行為 n 個升序整數
- 實作中通常生成 `range(1, n+1)`

**測試邊界**:
| 測試場景 | 最小 | 最大 | 典型 |
|---------|------|------|------|
| 陣列大小 | 1 | 10,000 | 100 |
| 元素值 | 1 | 10,000 | 1 ~ 10,000 |

---

### ❸ 例外處理

**Question**: 非法輸入/空輸入/格式錯誤要怎麼處理?

**Answer**:
```python
# 邊界檢查
- 空陣列: 回傳 NOT FOUND -1 cmp=0
- None 輸入: raise ValueError
- 非整數: raise TypeError
- 非升序: 不檢查(假設題目輸入合法)

# 預期輸出格式
- FOUND <idx> cmp=<count> # 成功
- NOT FOUND -1 cmp=<count> # 失敗
```

**實作中的檢查**:
- Python 型別提示檢查
- 邊界值檢查(left <= right)
- 合法輸入假設(升序保證)

---

### ❹ Edge Case

**Question**: 至少列出 1 個邊界案例

**Answer**: 列出 **4 個主要 edge case**

| Edge Case | 測試 | 結果 |
|-----------|------|------|
| **單元素陣列** | `[101]` 找 101 | ✅ FOUND 0 cmp=1 |
| **目標在起始** | `[101, 102, ...]` 找 101 | ✅ FOUND 0 cmp=1(L) / 4(B) |
| **目標在末尾** | `[97, 98, 99, 100, 101]` 找 101 | ✅ FOUND 4 cmp=5(L) / 3(B) |
| **目標不存在(在範圍內)** | `[1, 50, 150, 200]` 找 101 | ✅ NOT FOUND -1 cmp=4(L) / 2(B) |
| **目標不存在(超出範圍)** | `[101, 102, ...]` 找 100 | ✅ NOT FOUND -1 cmp=1(B) |

**為什麼重要**:
- 確保演算法在邊界情況下正確
- 驗證比較次數計算正確
- 測試 edge case 是 TDD 的關鍵

---

### ❺ 驗收標準

**Question**: 什麼樣的輸出才算對?學號參數值是多少?

**Answer**:

**正確輸出標準**:
```
✅ FOUND <idx> cmp=<N> # 找到目標,輸出索引和比較次數
✅ NOT FOUND -1 cmp=<N> # 未找到目標,輸出 -1 和比較次數
✅ 比較次數必須精確 # 每次檢查都要計算
✅ 時間測量: timeit 秒數 # 用 timeit 重複 1000 次
✅ 雷達圖: 比較性能差異 # 需要 matplotlib 繪製
```

**學號參數**:
- **學號**: 1114405001
- **搜尋目標 K**: 101
- **輸出路徑**: `assets/radar.png`

**驗收指標**:
- 12/12 測試通過 ✅
- 線性搜尋正確性 ✅
- 二分搜尋正確性 ✅
- 邊界情況全覆蓋 ✅
- 性能差異顯著 (Binary ~7x 快) ✅

---

## 🧪 Test Cases 設計流程

### 紅燈 (RED) 階段
```
1. 設計 12 個 test case(3 個主任務 + 額外邊界測試)
2. 建立 test_search.py
3. 執行測試 → 全部失敗(紅燈)✅
```

### 綠燈 (GREEN) 階段
```
1. 實作 linear_search()
2. 實作 binary_search()
3. 實作 SearchResult dataclass
4. 執行測試 → 全部通過(綠燈)✅
```

### 測試結果
```
============================= 12 passed in 0.07s ==============================

✅ Task 1: 小規模陣列 - 目標存在(2 個測試)
✅ Task 2: 大規模陣列 - 效能對比(3 個測試)
✅ Task 3: Edge Case - 目標不存在(3 個測試)
✅ 額外邊界測試(4 個測試)

全覆蓋:
- 正確性: ✅ 兩種搜尋結果相同
- 效能差異: ✅ Binary 快 7 倍以上
- 邊界條件: ✅ 單元素、起始、末尾、超出範圍
- 比較次數: ✅ 精確計算
```

---

## 📊 重點設計決策

### 為什麼分 3 個 Task?

| Task | 目的 | 難度 | 涵蓋 |
|------|------|------|------|
| **1. 小規模陣列** | 驗證基本邏輯 | ⭐ | 正確性 |
| **2. 大規模陣列** | 展示效能差異 | ⭐⭐ | **O(n) vs O(log n)** |
| **3. Edge Case** | 邊界處理 | ⭐⭐⭐ | 穩定性 |

### 為什麼用 DataClass?

```python
@dataclass
class SearchResult:
found: bool
index: int
comparisons: int
```

**好處**:
- 型別安全(IDE 自動完成)
- 代碼可讀性高
- 方便序列化(JSON/CSV for 雷達圖)
- 易於擴展(如加入執行時間)

### 為什麼計算比較次數?

- **單純時間測量** 容易受 CPU 影響
- **比較次數** 是演算法複雜度的直接指標
- **展示 O(n) vs O(log n)** 需要準確的計算操作數

---

## 🎯 後續步驟

已完成:
- ✅ 3 個 Task 的 12 個 test case
- ✅ linear_search + binary_search 實作
- ✅ 所有測試通過(綠燈)
- ✅ 3 個 git commit

待完成(PR 後):
- [ ] 編寫主程式(讀入陣列、呼叫搜尋、輸出結果)
- [ ] 用 timeit 測量執行時間
- [ ] 繪製雷達圖(radar.png)
- [ ] 輸出 assets/radar.png

---

## 📝 AI 協作要點

### ✅ 遵循的原則
1. **先測試後實作** (TDD): RED → GREEN → REFACTOR
2. **精確計算指標**: 比較次數、執行時間
3. **完整 edge case**: 邊界、單元素、不存在
4. **自我檢查**: 型別提示、代碼註解
5. **文件記錄**: TASK_SUMMARY.md + AI_LOG.md

### 🔍 自我審視
- ✅ 函式簽名明確
- ✅ 輸入邊界清楚
- ✅ 例外處理考慮
- ✅ Edge case 齊全
- ✅ 驗收標準具體

---

## 📌 總結

**本作答**遵循 CPE 課程的 **TDD 流程**:
1. **RED**: 12 個 test case 測試框架 → commit
2. **GREEN**: 實作搜尋演算法 → commit
3. **REFACTOR**: 文件整理 (TASK_SUMMARY.md) → commit

**關鍵成果**:
- 12/12 測試通過 (0.07s)
- 展示 Binary Search 的 O(log n) 優勢
- 完整覆蓋邊界和 edge case
- 清晰的代碼和文件

**下一步**: 開 PR 至課程 repo main 分支
138 changes: 138 additions & 0 deletions weeks/week-18/solutions/1114405001/TASK_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Week 18 - Binary Search vs Linear Search

## 📋 任務概述

**目標**:K = 101
**學號**:1114405001
**分支**:`feature/week18-1114405001`

---

## 🧪 3 個 Task 詳細說明

### Task 1️⃣: 小規模陣列 - 目標存在(中間位置)

**測試類別**:`TestTask1SmallArrayTargetFound`

| 測試項 | 內容 |
|--------|------|
| **目的** | 驗證基本搜尋邏輯正確性 |
| **測試陣列** | `[1, 50, 101, 150, 200]` |
| **搜尋目標** | 101(位置 index=2) |
| **Linear Search** | ✅ FOUND 2 cmp=3 |
| **Binary Search** | ✅ FOUND 2 cmp=≤3 |

**測試用例**:
- `test_linear_search_small_array_middle`: 驗證線性搜尋找到目標
- `test_binary_search_small_array_middle`: 驗證二分搜尋找到目標,比較次數 ≤ log₂(5)

**為何重要**:
- 驗證核心搜尋邏輯的正確性
- 建立簡單情況的基準測試

---

### Task 2️⃣: 大規模陣列 - 目標存在(效能顯著差異)

**測試類別**:`TestTask2LargeArrayTargetFound`

| 測試項 | 內容 |
|--------|------|
| **目的** | 驗證 Binary Search 的效能優勢 |
| **測試陣列** | `[1, 2, 3, ..., 10000]` |
| **搜尋目標** | 101(位置 index=100) |
| **Linear Search** | ✅ FOUND 100 cmp≈101 |
| **Binary Search** | ✅ FOUND 100 cmp≤14 |
| **性能比較** | Binary 比 Linear 快 **7 倍以上** |

**測試用例**:
- `test_linear_search_large_array`: 線性搜尋需 ~101 次比較
- `test_binary_search_large_array`: 二分搜尋需 ≤14 次比較(log₂(10000)≈13.3)
- `test_binary_search_much_faster_than_linear`: 驗證性能差異 ≥ 5 倍

**為何重要**:
- 展示演算法在大規模數據上的實際性能差異
- 演示 O(n) vs O(log n) 的具體優勢
- Edge case:展示指數級的效能改進

---

### Task 3️⃣: Edge Case - 目標不存在

**測試類別**:`TestTask3EdgeCaseNotFound`

| 測試項 | 內容 |
|--------|------|
| **目的** | 驗證 NOT FOUND 邏輯正確性 |
| **測試陣列** | `[1, 50, 150, 200]` |
| **搜尋目標** | 101(**不存在**) |
| **Linear Search** | ✅ NOT FOUND -1 cmp=4 |
| **Binary Search** | ✅ NOT FOUND -1 cmp≤4 |

**測試用例**:
- `test_linear_search_not_found`: 線性搜尋須檢查所有元素才確認不存在
- `test_binary_search_not_found`: 二分搜尋快速排除不存在的目標
- `test_target_not_in_range`: 目標超出陣列範圍(太小/太大)

**額外 Edge Cases**:
- 單元素陣列(存在/不存在)
- 目標在陣列起始位置
- 目標在陣列末尾位置

**為何重要**:
- 確保搜尋演算法的完整性
- 驗證邊界條件的正確處理
- 實際應用中很常見的情況

---

## ✅ 測試結果

```
============================= test session starts =============================
collected 12 items

test_search.py::TestTask1SmallArrayTargetFound::test_linear_search_small_array_middle PASSED [ 8%]
test_search.py::TestTask1SmallArrayTargetFound::test_binary_search_small_array_middle PASSED [ 16%]
test_search.py::TestTask2LargeArrayTargetFound::test_linear_search_large_array PASSED [ 25%]
test_search.py::TestTask2LargeArrayTargetFound::test_binary_search_large_array PASSED [ 33%]
test_search.py::TestTask2LargeArrayTargetFound::test_binary_search_much_faster_than_linear PASSED [ 41%]
test_search.py::TestTask3EdgeCaseNotFound::test_linear_search_not_found PASSED [ 50%]
test_search.py::TestTask3EdgeCaseNotFound::test_binary_search_not_found PASSED [ 58%]
test_search.py::TestTask3EdgeCaseNotFound::test_target_not_in_range PASSED [ 66%]
test_search.py::TestEdgeCasesAdditional::test_single_element_array_found PASSED [ 75%]
test_search.py::TestEdgeCasesAdditional::test_single_element_array_not_found PASSED [ 83%]
test_search.py::TestEdgeCasesAdditional::test_target_at_start PASSED [ 91%]
test_search.py::TestEdgeCasesAdditional::test_target_at_end PASSED [100%]

============================= 12 passed in 0.07s ==============================
```

---

## 📊 Git Commit 記錄

| Commit | 說明 |
|--------|------|
| `4dce6f9` | **RED**: 3 個 Task 的 12 個測試用例 |
| `cae710f` | **GREEN**: 線性搜尋 + 二分搜尋實作,所有測試通過 |

---

## 📁 檔案結構

```
weeks/week-18/solutions/1114405001/
├── test_search.py # 測試文件(12 個 test cases)
├── search.py # 實作文件(linear_search, binary_search)
└── TASK_SUMMARY.md # 本文件
```

---

## 🎯 下一步

檢查完畢後,將進行:
- [ ] 3. 合併結果 + 編寫 AI_LOG.md
- [ ] 4. push 到遠端
- [ ] 5. 開 PR(自己的 fork → 課程 repo main)
Loading