Skip to content

Commit c901bea

Browse files
committed
feat: add dual algorithm views (DFS/BFS), property tests, and GitHub Actions deployment
1 parent 128d927 commit c901bea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+5598
-72
lines changed

.github/workflows/deploy.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Deploy to GitHub Pages
22

33
on:
44
push:
5-
branches: [main, master]
5+
branches: [main]
66
workflow_dispatch:
77

88
permissions:
@@ -12,7 +12,7 @@ permissions:
1212

1313
concurrency:
1414
group: pages
15-
cancel-in-progress: true
15+
cancel-in-progress: false
1616

1717
jobs:
1818
build:
@@ -30,11 +30,14 @@ jobs:
3030
- name: Install dependencies
3131
run: npm ci
3232

33+
- name: Run tests
34+
run: npm test
35+
3336
- name: Build
3437
run: npm run build
3538

3639
- name: Setup Pages
37-
uses: actions/configure-pages@v4
40+
uses: actions/configure-pages@v5
3841

3942
- name: Upload artifact
4043
uses: actions/upload-pages-artifact@v3
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
# Design Document
2+
3+
## Overview
4+
5+
本功能为 LeetCode 199「二叉树的右视图」算法可视化项目添加双解法支持。用户可以从导航栏选择 DFS(深度优先搜索)或 BFS(广度优先搜索/层序遍历)两种解法,每种解法有独立的画布和可视化界面。BFS 解法在画布上展示队列数据结构的可视化,帮助用户理解层序遍历的工作原理。
6+
7+
## Architecture
8+
9+
### 整体架构变更
10+
11+
```
12+
┌─────────────────────────────────────────────────────────────┐
13+
│ App (主容器) │
14+
├─────────────────────────────────────────────────────────────┤
15+
│ Header (标题栏) │
16+
├─────────────────────────────────────────────────────────────┤
17+
│ AlgorithmSelector (算法选择器) [新增] │
18+
│ ├── DFSButton (DFS 解法按钮) │
19+
│ └── BFSButton (BFS 解法按钮) │
20+
├─────────────────────────────────────────────────────────────┤
21+
│ DataInput (数据输入区) [共享] │
22+
├─────────────────────────────────────────────────────────────┤
23+
│ MainContent (主内容区) │
24+
│ ├── DFSView [条件渲染] │ BFSView [条件渲染] │
25+
│ │ ├── DFSCodePanel │ ├── BFSCodePanel │
26+
│ │ └── DFSCanvas │ └── BFSCanvas │
27+
│ │ │ └── QueueVisualization│
28+
├─────────────────────────────────────────────────────────────┤
29+
│ PlaybackControls (播放控制) [共享,状态独立] │
30+
└─────────────────────────────────────────────────────────────┘
31+
```
32+
33+
### 状态管理架构
34+
35+
```
36+
AppState
37+
├── inputValue: string // 共享输入数据
38+
├── tree: TreeNode | null // 共享二叉树
39+
├── currentAlgorithm: 'dfs' | 'bfs' // 当前选中算法
40+
├── dfsState // DFS 视图状态
41+
│ ├── steps: AnimationStep[]
42+
│ ├── currentStepIndex: number
43+
│ └── isPlaying: boolean
44+
└── bfsState // BFS 视图状态
45+
├── steps: BFSAnimationStep[]
46+
├── currentStepIndex: number
47+
└── isPlaying: boolean
48+
```
49+
50+
## Components and Interfaces
51+
52+
### 新增组件
53+
54+
#### 1. AlgorithmSelector (src/components/AlgorithmSelector/)
55+
算法选择器组件,用于切换 DFS 和 BFS 视图。
56+
57+
```typescript
58+
interface AlgorithmSelectorProps {
59+
currentAlgorithm: 'dfs' | 'bfs';
60+
onAlgorithmChange: (algorithm: 'dfs' | 'bfs') => void;
61+
}
62+
```
63+
64+
#### 2. BFSCodePanel (src/components/BFSCodePanel/)
65+
BFS 代码面板组件,展示 BFS 算法代码。
66+
67+
```typescript
68+
interface BFSCodePanelProps {
69+
highlightLines: number[];
70+
variables: Record<string, unknown>;
71+
queueState: QueueItem[];
72+
}
73+
```
74+
75+
#### 3. QueueVisualization (src/components/QueueVisualization/)
76+
队列可视化组件,在画布下方展示队列状态。
77+
78+
```typescript
79+
interface QueueVisualizationProps {
80+
queue: QueueItem[];
81+
highlightedNodeId?: string;
82+
onDequeue?: () => void;
83+
onEnqueue?: (item: QueueItem) => void;
84+
}
85+
86+
interface QueueItem {
87+
nodeId: string;
88+
value: number;
89+
isHighlighted?: boolean;
90+
}
91+
```
92+
93+
### 修改组件
94+
95+
#### App (src/App.tsx)
96+
扩展状态管理,支持双视图状态独立。
97+
98+
```typescript
99+
interface AppState {
100+
inputValue: string;
101+
tree: TreeNode | null;
102+
currentAlgorithm: 'dfs' | 'bfs';
103+
language: Language;
104+
dfsState: {
105+
steps: AnimationStep[];
106+
currentStepIndex: number;
107+
isPlaying: boolean;
108+
};
109+
bfsState: {
110+
steps: BFSAnimationStep[];
111+
currentStepIndex: number;
112+
isPlaying: boolean;
113+
};
114+
}
115+
```
116+
117+
## Data Models
118+
119+
### BFSAnimationStep (BFS 动画步骤)
120+
121+
```typescript
122+
interface BFSAnimationStep {
123+
type: 'init' | 'dequeue' | 'enqueue-left' | 'enqueue-right' | 'record-result' | 'level-complete' | 'return';
124+
nodeId?: string; // 当前操作的节点 ID
125+
level?: number; // 当前层号
126+
description: string; // 步骤描述
127+
highlightLines: { // 各语言高亮行号
128+
java: number[];
129+
python: number[];
130+
golang: number[];
131+
javascript: number[];
132+
};
133+
variables: Record<string, unknown>; // 变量状态
134+
resultSoFar: number[]; // 当前结果数组
135+
queueState: QueueItem[]; // 当前队列状态
136+
nodeStates: Map<string, NodeState>; // 节点状态映射
137+
annotations?: Annotation[]; // 画布标注
138+
}
139+
140+
type NodeState = 'unvisited' | 'in-queue' | 'processing' | 'completed' | 'result';
141+
```
142+
143+
### QueueItem (队列项)
144+
145+
```typescript
146+
interface QueueItem {
147+
nodeId: string; // 节点 ID
148+
value: number; // 节点值
149+
level: number; // 所在层级
150+
}
151+
```
152+
153+
### BFS 代码片段
154+
155+
```typescript
156+
// src/constants/bfsCodeSnippets.ts
157+
export const bfsCodeSnippets = {
158+
java: `class Solution {
159+
public List<Integer> rightSideView(TreeNode root) {
160+
List<Integer> ans = new ArrayList<>();
161+
if (root == null) return ans;
162+
163+
Queue<TreeNode> queue = new LinkedList<>();
164+
queue.offer(root);
165+
166+
while (!queue.isEmpty()) {
167+
int levelSize = queue.size();
168+
for (int i = 0; i < levelSize; i++) {
169+
TreeNode node = queue.poll();
170+
if (i == levelSize - 1) {
171+
ans.add(node.val);
172+
}
173+
if (node.left != null) queue.offer(node.left);
174+
if (node.right != null) queue.offer(node.right);
175+
}
176+
}
177+
return ans;
178+
}
179+
}`,
180+
// ... python, golang, javascript
181+
};
182+
```
183+
184+
## Correctness Properties
185+
186+
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
187+
188+
### Property 1: 输入数据跨视图同步
189+
*For any* 输入数据修改操作,无论在 DFS 还是 BFS 视图中进行,切换到另一个视图后输入数据应保持一致。
190+
**Validates: Requirements 1.5, 6.3**
191+
192+
### Property 2: 视图切换重置播放状态
193+
*For any* 视图切换操作,切换后当前视图的动画步骤索引应重置为 0。
194+
**Validates: Requirements 1.6, 6.4**
195+
196+
### Property 3: BFS 动画步骤包含队列状态
197+
*For any* BFS 动画步骤,该步骤的 queueState 字段应包含当前队列中所有节点的信息。
198+
**Validates: Requirements 3.2**
199+
200+
### Property 4: BFS 队列操作步骤标记正确性
201+
*For any* BFS 动画中的入队或出队操作,步骤类型应正确标记为 'enqueue-left'、'enqueue-right' 或 'dequeue',且包含对应节点信息。
202+
**Validates: Requirements 3.4, 3.5**
203+
204+
### Property 5: BFS 右视图结果正确性
205+
*For any* 非空二叉树,BFS 算法生成的右视图结果应等于每层最后一个节点值的集合。
206+
**Validates: Requirements 3.6**
207+
208+
### Property 6: BFS 代码高亮行有效性
209+
*For any* BFS 动画步骤和任意支持的语言,该步骤的 highlightLines 应包含该语言对应的有效行号数组,且行号在 BFS 代码范围内。
210+
**Validates: Requirements 2.2**
211+
212+
### Property 7: 队列与树节点高亮同步
213+
*For any* 被高亮的树节点,如果该节点在队列中,则队列可视化中对应的方块应同步高亮。
214+
**Validates: Requirements 4.7**
215+
216+
### Property 8: BFS 节点状态转换正确性
217+
*For any* BFS 动画执行过程中的节点,其状态应按照 unvisited → in-queue → processing → completed/result 的顺序转换,不应跳过中间状态。
218+
**Validates: Requirements 5.2, 5.3, 5.4, 5.5**
219+
220+
### Property 9: 视图状态往返恢复
221+
*For any* 视图切换序列(如 DFS → BFS → DFS),返回原视图后播放进度应恢复到切换前的状态。
222+
**Validates: Requirements 6.1, 6.2**
223+
224+
## Error Handling
225+
226+
### 视图切换错误处理
227+
- 切换时动画正在播放:自动暂停当前动画
228+
- 切换时数据无效:保持在当前视图并显示错误提示
229+
230+
### 队列可视化错误处理
231+
- 队列为空:显示空队列占位符
232+
- 队列过长超出显示区域:启用水平滚动或压缩显示
233+
234+
### 状态同步错误处理
235+
- 状态不一致:以最新输入数据为准重新生成动画步骤
236+
237+
## Testing Strategy
238+
239+
### 单元测试
240+
使用 Vitest 进行单元测试:
241+
- BFS 动画步骤生成函数测试
242+
- 队列状态管理函数测试
243+
- 视图状态切换函数测试
244+
245+
### 属性测试
246+
使用 fast-check 进行属性测试:
247+
- 每个属性测试运行至少 100 次迭代
248+
- 测试文件使用 `*.property.test.ts` 命名
249+
- 每个测试用注释标注对应的 Property 编号和 Requirements
250+
251+
**属性测试标注格式:**
252+
```typescript
253+
// **Feature: dual-algorithm-views, Property 1: 输入数据跨视图同步**
254+
// **Validates: Requirements 1.5, 6.3**
255+
```
256+
257+
### 测试文件结构
258+
```
259+
src/
260+
├── utils/
261+
│ ├── bfsAlgorithm.ts
262+
│ ├── bfsAlgorithm.property.test.ts # BFS 属性测试
263+
│ └── viewState.property.test.ts # 视图状态属性测试
264+
├── components/
265+
│ ├── QueueVisualization/
266+
│ │ └── QueueVisualization.test.tsx
267+
│ └── AlgorithmSelector/
268+
│ └── AlgorithmSelector.test.tsx
269+
```
270+
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Requirements Document
2+
3+
## Introduction
4+
5+
本功能为 LeetCode 199「二叉树的右视图」算法可视化项目添加双解法支持。用户可以从导航栏选择 DFS(深度优先搜索)或 BFS(广度优先搜索/层序遍历)两种解法,每种解法有独立的画布和可视化界面。BFS 解法需要在画布上展示队列数据结构的可视化。
6+
7+
## Glossary
8+
9+
- **Algorithm_Visualizer**: 算法可视化系统,负责将算法执行过程以动画形式展示
10+
- **DFS_View**: 深度优先搜索视图,展示 DFS 解法的可视化界面
11+
- **BFS_View**: 广度优先搜索视图,展示 BFS 解法的可视化界面
12+
- **Queue_Visualization**: 队列可视化组件,在 BFS 视图中展示当前队列状态
13+
- **Algorithm_Selector**: 算法选择器,位于导航栏,用于切换 DFS 和 BFS 解法
14+
- **Animation_Step**: 动画步骤,算法执行的最小可视化单元
15+
- **Canvas**: 画布组件,使用 D3.js 绘制二叉树和数据结构的可视化区域
16+
17+
## Requirements
18+
19+
### Requirement 1: 算法选择导航
20+
21+
**User Story:** As a 用户, I want 从导航栏选择不同的算法解法, so that 我能学习和对比 DFS 和 BFS 两种解题思路。
22+
23+
#### Acceptance Criteria
24+
25+
1. WHEN 页面加载完成 THEN THE Algorithm_Selector SHALL 在标题栏下方显示「DFS 解法」和「BFS 解法」两个切换按钮
26+
2. WHEN 用户单击「DFS 解法」按钮 THEN THE Algorithm_Visualizer SHALL 切换到 DFS 视图并高亮该按钮
27+
3. WHEN 用户单击「BFS 解法」按钮 THEN THE Algorithm_Visualizer SHALL 切换到 BFS 视图并高亮该按钮
28+
4. WHEN 页面首次加载 THEN THE Algorithm_Visualizer SHALL 默认显示 DFS 视图
29+
5. WHEN 用户切换解法 THEN THE Algorithm_Visualizer SHALL 保留当前输入的二叉树数据
30+
6. WHEN 用户切换解法 THEN THE Algorithm_Visualizer SHALL 重置动画播放状态到第一步
31+
32+
### Requirement 2: BFS 算法代码展示
33+
34+
**User Story:** As a 用户, I want 查看 BFS 解法的多语言代码, so that 我能学习层序遍历的实现方式。
35+
36+
#### Acceptance Criteria
37+
38+
1. WHEN BFS 视图激活 THEN THE Code_Panel SHALL 显示 BFS 算法代码并支持 Java、Python、Go、JavaScript 四种语言
39+
2. WHEN BFS 动画步骤变化 THEN THE Code_Panel SHALL 高亮显示当前执行的 BFS 代码行
40+
3. WHEN BFS 代码显示 THEN THE Code_Panel SHALL 在高亮行后方显示队列和当前层相关变量的值
41+
42+
### Requirement 3: BFS 动画步骤生成
43+
44+
**User Story:** As a 用户, I want 看到 BFS 算法的分步执行过程, so that 我能理解层序遍历的工作原理。
45+
46+
#### Acceptance Criteria
47+
48+
1. WHEN 用户在 BFS 视图运行算法 THEN THE Algorithm_Visualizer SHALL 生成层序遍历的动画步骤序列
49+
2. WHEN BFS 动画步骤生成 THEN THE Animation_Step SHALL 包含当前队列状态信息
50+
3. WHEN BFS 处理一层节点 THEN THE Animation_Step SHALL 记录当前层的所有节点和层号
51+
4. WHEN BFS 将节点出队 THEN THE Animation_Step SHALL 标记出队操作和出队节点
52+
5. WHEN BFS 将子节点入队 THEN THE Animation_Step SHALL 标记入队操作和入队节点
53+
6. WHEN BFS 记录右视图节点 THEN THE Animation_Step SHALL 标记每层最后一个节点为右视图结果
54+
55+
### Requirement 4: 队列可视化
56+
57+
**User Story:** As a 用户, I want 在画布上看到队列的可视化, so that 我能直观理解 BFS 中队列的变化过程。
58+
59+
#### Acceptance Criteria
60+
61+
1. WHEN BFS 视图激活且二叉树存在 THEN THE Queue_Visualization SHALL 在画布下方显示队列可视化区域
62+
2. WHEN 队列可视化显示 THEN THE Queue_Visualization SHALL 以水平排列的方块展示队列中的节点值
63+
3. WHEN 节点入队 THEN THE Queue_Visualization SHALL 在队列右侧添加新方块并播放入队动画
64+
4. WHEN 节点出队 THEN THE Queue_Visualization SHALL 从队列左侧移除方块并播放出队动画
65+
5. WHEN 队列为空 THEN THE Queue_Visualization SHALL 显示空队列状态标识
66+
6. WHEN 队列可视化显示 THEN THE Queue_Visualization SHALL 在队列上方显示「队列 Queue」标签
67+
7. WHEN 队列中节点对应树中被高亮节点 THEN THE Queue_Visualization SHALL 同步高亮队列中对应的方块
68+
69+
### Requirement 5: BFS 画布节点状态
70+
71+
**User Story:** As a 用户, I want 在 BFS 视图中看到节点的不同状态, so that 我能区分已访问、正在处理和待访问的节点。
72+
73+
#### Acceptance Criteria
74+
75+
1. WHEN BFS 动画执行 THEN THE Canvas SHALL 使用不同颜色区分:未访问节点、队列中节点、正在处理节点、已完成节点
76+
2. WHEN 节点被加入队列 THEN THE Canvas SHALL 将该节点标记为「队列中」状态
77+
3. WHEN 节点从队列取出处理 THEN THE Canvas SHALL 将该节点标记为「正在处理」状态
78+
4. WHEN 节点处理完成 THEN THE Canvas SHALL 将该节点标记为「已完成」状态
79+
5. WHEN 节点被记录为右视图结果 THEN THE Canvas SHALL 使用特殊颜色标记该节点
80+
81+
### Requirement 6: 视图状态独立
82+
83+
**User Story:** As a 用户, I want DFS 和 BFS 视图的播放状态相互独立, so that 切换视图时不会丢失之前的进度。
84+
85+
#### Acceptance Criteria
86+
87+
1. WHEN 用户从 DFS 切换到 BFS 再切回 DFS THEN THE Algorithm_Visualizer SHALL 恢复 DFS 视图之前的播放进度
88+
2. WHEN 用户从 BFS 切换到 DFS 再切回 BFS THEN THE Algorithm_Visualizer SHALL 恢复 BFS 视图之前的播放进度
89+
3. WHEN 用户在一个视图修改输入数据 THEN THE Algorithm_Visualizer SHALL 同步更新另一个视图的输入数据
90+
4. WHEN 输入数据变化 THEN THE Algorithm_Visualizer SHALL 重置两个视图的动画步骤
91+

0 commit comments

Comments
 (0)