Skip to content
Merged
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
145 changes: 145 additions & 0 deletions .auto-dev/prd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# PRD: 冒泡排序可视化

## 1. 算法定义和边界

### 算法描述
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数组,依次比较相邻的两个元素,如果顺序错误就交换它们。遍历数组的工作重复进行,直到没有需要交换的元素为止。

### 算法边界
- 输入:整数数组(支持正数、负数、零)
- 输出:升序排列的数组
- 稳定性:稳定排序
- 时间复杂度:O(n²)(最坏和平均情况),O(n)(最好情况,已排序数组)
- 空间复杂度:O(1),原地排序

### 不变量
- 每一轮遍历后,当前未排序部分的最大值会被"冒泡"到正确位置
- 外层循环控制轮次,内层循环执行相邻比较和交换

## 2. 输入规模和示例数据

### 输入规模
- 最小长度:2 个元素
- 最大长度:20 个元素(可视化展示限制)
- 默认长度:8 个元素
- 元素值范围:-99 到 99

### 示例数据
```
默认数组: [64, 34, 25, 12, 22, 11, 90, 1]
随机生成: 用户指定长度,随机生成整数数组
自定义输入: 用户手动输入逗号分隔的整数
```

## 3. 可视化步骤和交互控件

### 可视化步骤
算法执行过程分解为多个步骤,每一步包含:
1. **比较操作**:高亮当前正在比较的两个相邻元素
2. **交换操作**:如果顺序错误,执行交换并动画展示移动过程
3. **标记完成**:每轮结束后,标记已排序区域

### 步骤数据结构
```javascript
{
array: [当前数组状态],
comparing: [index1, index2], // 正在比较的元素索引
swapping: [index1, index2], // 正在交换的元素索引(如果发生交换)
sorted: [indices], // 已排序区域的索引
round: number, // 当前轮次
description: string // 当前步骤说明
}
```

### 交互控件
1. **输入控制**
- 文本输入框:手动输入数组(逗号分隔)
- 长度滑块:设置随机数组长度(2-20)
- 随机生成按钮:生成指定长度的随机数组
- 确认按钮:开始排序

2. **播放控制**(复用 PageRank 模式)
- 播放/暂停按钮
- 下一步按钮
- 上一步按钮(支持回退)
- 重置按钮
- 速度控制滑块

3. **显示控制**
- 说明面板:显示当前步骤的文字描述
- 统计面板:显示比较次数、交换次数、当前轮次

### 视觉设计
- 数组元素用矩形条表示,高度映射数值大小
- 当前比较的元素高亮显示(黄色)
- 交换中的元素用动画过渡(蓝色)
- 已排序区域用不同颜色标记(绿色)
- 使用 Framer Motion 实现平滑动画

## 4. 复杂度说明

### 时间复杂度
- 最好情况:O(n),数组已排序,只需遍历一次
- 最坏情况:O(n²),数组逆序,需要 n-1 轮遍历
- 平均情况:O(n²)

### 空间复杂度
- O(1),原地排序,只需要常数级额外空间

### 可视化复杂度
- 步骤数量:最多 n*(n-1)/2 次比较,最多 n*(n-1)/2 次交换
- 动画帧数:每步 300-500ms,总时长可控

## 5. 验收清单

### 功能验收
- [ ] 支持用户手动输入数组(逗号分隔整数)
- [ ] 支持随机生成指定长度数组(2-20个元素)
- [ ] 正确实现冒泡排序算法
- [ ] 可视化展示每一步比较和交换操作
- [ ] 支持单步执行(下一步/上一步)
- [ ] 支持自动播放(播放/暂停)
- [ ] 支持重置到初始状态
- [ ] 显示当前步骤的文字说明
- [ ] 显示统计信息(比较次数、交换次数、轮次)

### 视觉验收
- [ ] 数组元素用矩形条可视化,高度映射数值
- [ ] 当前比较的元素高亮显示
- [ ] 交换操作有平滑动画
- [ ] 已排序区域有明显标记
- [ ] 响应式布局,适配不同屏幕尺寸

### 技术验收
- [ ] 算法模块为纯函数,零 DOM/React 依赖
- [ ] 算法模块导出 `computeSteps(input)` 和 `runAlgorithmTests()`
- [ ] 算法模块通过 Node ESM import 自检
- [ ] 动画组件复用现有 UI 组件(button, card)
- [ ] 动画组件复用 PageRank 的播放控制模式
- [ ] 在 `src/App.jsx` 注册路由
- [ ] `npm run build` 构建通过

## 6. 建议文件 slug

```
bubble-sort
```

### 文件结构
```
src/animations/bubble-sort/
algorithm.js # 算法纯函数
src/animations/bubble-sort.jsx # 动画组件
```

### 路由配置
```javascript
// src/App.jsx
{
id: 'bubble-sort',
name: '冒泡排序',
description: '经典排序算法可视化',
path: '/bubble-sort',
component: BubbleSortAnimation
}
```
57 changes: 57 additions & 0 deletions .auto-dev/qa-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# QA Report: 冒泡排序可视化 (Issue #4)

## 构建结果

**PASS** — `npm run build` 成功完成,无错误。

## 算法测试结果

**PASS** — `runAlgorithmTests()` 全部断言通过。

测试覆盖:基本排序、已排序数组(提前退出)、逆序数组、单次交换、负数、两元素、重复值、索引合法性、步骤计数、PRD 示例数据。

## 验收清单

### 功能验收

| # | 验收项 | 结果 | 说明 |
|---|--------|------|------|
| 1 | 支持用户手动输入数组(逗号分隔整数) | ✅ PASS | `parseInput` 支持逗号/中文逗号/空格分隔,输入框 + "排序"按钮 |
| 2 | 支持随机生成指定长度数组(2-20个元素) | ✅ PASS | 滑块 min=2 max=20,`randomArray` 生成 -99~99 范围整数 |
| 3 | 正确实现冒泡排序算法 | ✅ PASS | 算法测试覆盖多种场景,全部通过 |
| 4 | 可视化展示每一步比较和交换操作 | ✅ PASS | 柱状图高亮比较(amber)和交换(blue)元素 |
| 5 | 支持单步执行(下一步/上一步) | ✅ PASS | goNext/goPrev 回调实现 |
| 6 | 支持自动播放(播放/暂停) | ✅ PASS | useEffect 定时器自动推进,播放/暂停按钮切换 |
| 7 | 支持重置到初始状态 | ✅ PASS | handleReset 回到 step 0 |
| 8 | 显示当前步骤的文字说明 | ✅ PASS | "当前步骤"面板显示 description |
| 9 | 显示统计信息(比较次数、交换次数、轮次) | ✅ PASS | 三个统计卡片显示 comparisons/swaps/round |

### 视觉验收

| # | 验收项 | 结果 | 说明 |
|---|--------|------|------|
| 1 | 数组元素用矩形条可视化,高度映射数值 | ✅ PASS | heightPct 基于 Math.abs(value)/maxVal 计算 |
| 2 | 当前比较的元素高亮显示 | ✅ PASS | amber-400 高亮 + scale 1.08 |
| 3 | 交换操作有平滑动画 | ✅ PASS | Framer Motion layout + spring 动画 |
| 4 | 已排序区域有明显标记 | ✅ PASS | emerald-500 绿色 + ✓ 标记 |
| 5 | 响应式布局,适配不同屏幕尺寸 | ✅ PASS | grid lg:grid-cols-[1.35fr_1fr],flex-wrap |

### 技术验收

| # | 验收项 | 结果 | 说明 |
|---|--------|------|------|
| 1 | 算法模块为纯函数,零 DOM/React 依赖 | ✅ PASS | 仅使用数组操作和 console.assert |
| 2 | 算法模块导出 computeSteps(input) 和 runAlgorithmTests() | ✅ PASS | 两个命名导出 |
| 3 | 算法模块通过 Node ESM import 自检 | ✅ PASS | Node 直接运行通过 |
| 4 | 动画组件复用现有 UI 组件(button, card) | ✅ PASS | 导入 Button, Card, CardContent |
| 5 | 动画组件复用 PageRank 的播放控制模式 | ✅ PASS | 相同的 playing/speed/stepIndex 模式 |
| 6 | 在 src/App.jsx 注册路由 | ✅ PASS | animations 数组中 id='bubble-sort' |
| 7 | npm run build 构建通过 | ✅ PASS | 1.71s 完成 |

## 发现的问题

无。

## 结论

全部验收项通过,无缺陷。
97 changes: 97 additions & 0 deletions .auto-dev/status/issue-4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"issue": 4,
"title": "冒泡排序",
"current_stage": "pr_opened",
"current_owner": "qa",
"pinned_comment_id": 4362742036,
"pr_url": "https://github.com/fengwm64/vis/pull/5",
"history": [
{
"ts": "2026-05-02T03:01:46.091Z",
"from": "system",
"to": "pm",
"stage": "submitted",
"artifact": ".auto-dev/incoming/issue-4.md",
"message": "Issue submitted and queued for PM triage."
},
{
"ts": "2026-05-02T03:02:02.241Z",
"from": "system",
"to": "pm",
"stage": "pm_triage",
"artifact": ".auto-dev/incoming/issue-4.md",
"message": "PM triage started."
},
{
"ts": "2026-05-02T03:02:32.010Z",
"from": "pm",
"to": "algorithm",
"stage": "prd_done",
"artifact": ".auto-dev/prd.md",
"message": "PRD is ready."
},
{
"ts": "2026-05-02T03:02:57.996Z",
"from": "pm",
"to": "algorithm",
"stage": "algorithm_designing",
"artifact": ".auto-dev/prd.md",
"message": "Algorithm design started."
},
{
"ts": "2026-05-02T03:03:48.812Z",
"from": "algorithm",
"to": "frontend",
"stage": "algorithm_done",
"artifact": "src/animations/bubble-sort/algorithm.js",
"message": "Algorithm module and tests are ready."
},
{
"ts": "2026-05-02T03:04:20.656Z",
"from": "algorithm",
"to": "frontend",
"stage": "frontend_designing",
"artifact": ".auto-dev/prd.md",
"message": "Frontend design started."
},
{
"ts": "2026-05-02T03:05:32.771Z",
"from": "frontend",
"to": "qa",
"stage": "frontend_done",
"artifact": "src/animations/bubble-sort.jsx",
"message": "Frontend animation is ready."
},
{
"ts": "2026-05-02T03:06:02.035Z",
"from": "frontend",
"to": "qa",
"stage": "qa_running",
"artifact": ".auto-dev/prd.md",
"message": "QA started."
},
{
"ts": "2026-05-02T03:06:38.839Z",
"from": "qa",
"to": "qa",
"stage": "qa_passed",
"artifact": ".auto-dev/qa-report.md",
"message": "QA passed."
},
{
"ts": "2026-05-02T03:06:51.969Z",
"from": "qa",
"to": "maintainer",
"stage": "pr_opened",
"artifact": ".auto-dev/qa-report.md",
"message": "PR opened by start.sh finalizer."
}
],
"retry_count": {
"qa_to_frontend": 0,
"qa_to_algorithm": 0,
"frontend_to_algorithm": 0,
"algorithm_to_pm": 0,
"frontend_to_pm": 0
}
}
8 changes: 8 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import { Routes, Route, Link, useLocation, useNavigate } from 'react-router-dom'
import PageRankProcessAnimation from './animations/pagerank_process_animation'
import BubbleSortAnimation from './animations/bubble-sort'
import Submit from './pages/Submit'
import Status from './pages/Status'
import { Button } from './components/ui/button'
Expand All @@ -13,6 +14,13 @@ const animations = [
path: '/animations/pagerank',
component: PageRankProcessAnimation,
},
{
id: 'bubble-sort',
title: '冒泡排序',
description: '经典排序算法可视化,支持自定义数组和随机生成,展示每一步比较和交换过程。',
path: '/animations/bubble-sort',
component: BubbleSortAnimation,
},
]

function GitHubIcon({ className }) {
Expand Down
Loading