核心问题:
- 算法层面的错误如何修复?
- 如何逐步扩展 C 子集?
- 如何支持数据结构教学?
最后核对日期:2026-10-04(S8 收官回灌——算法识别/推断已随 teaching/steps 落地:43 族判据+43 推断 + 311/311 标注 golden 对拍 + compile 帧
algorithm_matcheswire 出口,见S8 总览;§7 G9 缺口叙述保留为历史口径。前一沿革 2026-09-29 全库逐份翻新复核) 阶段完成状态:Phase 1 / Phase 2 / Phase 3 已完成、Phase 4 部分完成(OCR 项已随前端切割作废,OJ 项保留待做);前端切割后本仓库只做后端,算法验证/可视化能力以"后端能力 + 三出口载荷"形态保留。 修订说明(2026-09-11):去前端化——清除前端桥接实现位置与前端集成段落,改为语言中立后端能力与三出口(capi / wasm32 /vitro_cli serve)载荷;Phase 4 的 OCR 项标注作废;带日期的历史条目保持原样。
1. 算法层面的修复
1.1 算法错误的本质
算法层面的错误与语法/语义错误的根本区别:
| 错误层级 | 示例 | 编译器能否发现? | 运行时能否崩溃? |
|---|---|---|---|
| 语法错误 | inta = 5(缺空格) |
✅ 能 | ❌ 不运行 |
| 语义错误 | arr[10](数组越界) |
⚠️ 部分能 | ✅ 运行时 trap |
| 算法错误 | 冒泡排序边界 i < n 应为 i < n-1 |
❌ 不能 | ❌ 不崩溃,但结果错误 |
| 算法错误 | 快排分区逻辑写错 | ❌ 不能 | ❌ 不崩溃,但结果错误 |
| 算法错误 | 递归缺少终止条件 | ⚠️ 部分能 | ✅ 栈溢出 |
核心洞察:算法错误 = 语法正确 + 意图可识别 + 实现有偏差
1.2 三级算法修复策略
学生代码
↓
┌─────────────────────────────────────────────┐
│ Level 1: 算法模式识别(AST 层) │
│ • 将学生代码与已知算法模板进行结构匹配 │
│ • 识别"这是冒泡排序"、"这是二分查找" │
│ • 对比边界条件、循环变量的差异 │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Level 2: 运行时验证(Property-based Testing)│
│ • 自动生成测试用例 │
│ • 调用学生代码 + 验证结果属性 │
│ • 如果不通过,定位可疑代码区域 │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Level 3: 执行轨迹分析(Trace Analysis) │
│ • 记录 VitroVM 执行轨迹(比较/交换/递归调用) │
│ • 与标准轨迹对比 │
│ • 发现"少比较了一次"、"少交换了一次"等 │
└─────────────────────────────────────────────┘
1.3 Level 1: 算法模式识别
1.3.1 算法模板库
当前系统内置 88 个代码模板(82 个 C + 6 个 C++,见 模板维护指南.md §1;本节首版时为 43 个,C++ 批次后扩至 88,C++ 线已随砍 C++ 裁定冻结),分为 9 大类:
| 类别 | 数量 | 包含模板 |
|---|---|---|
| 排序 | 8 | 冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序、希尔排序、计数排序 |
| 查找 | 2 | 线性查找、二分查找 |
| 图算法 | 2 | BFS 广度优先搜索、DFS 深度优先搜索 |
| 动态规划 | 2 | 斐波那契数列、01 背包 |
| 数据结构 | 17 | 顺序表、链表节点/头插/尾插/遍历/删除/双向链表/循环链表、二叉树节点/先序/中序/后序/层序遍历、BST 插入与查找、链栈、链队列、循环队列、哈希表(线性探测)、约瑟夫环 |
| 字符串 | 1 | 字符串反转 |
| 基础 | 5 | 数组遍历求和、数组求最大值、指针交换两数、GCD 欧几里得、素数判断 |
| 递归 | 3 | 阶乘、斐波那契、汉诺塔 |
| 指针 | 1 | 指针基础操作 |
模板实现为 templates/<key>/source.c 文件 + meta.yaml 元数据(占位符语法 /*__PARAM_n__*/ 5,见模板维护指南.md §3)。每个模板附带 TutorialStep 列表定义算法执行阶段(outer_loop / compare / swap / partition / merge / enqueue / dequeue / visit / finish 等),以及 LineExplanation 关键行中文解释(TutorialStep/LineExplanation 的 Dart widget 载体已随前端切割迁出,缺口记录见本文 §7)。
1.3.2 AST 结构匹配算法
class AlgorithmMatcher {
public:
MatchResult Match(const FuncDecl& studentFunc) {
for (const auto& tmpl : templates) {
auto similarity = CalculateSimilarity(studentFunc, tmpl.astPattern);
if (similarity > 0.7f) { // 相似度阈值
return {
.matched = true,
.algorithm = tmpl.name,
.similarity = similarity,
.deviations = FindDeviations(studentFunc, tmpl)
};
}
}
return {.matched = false};
}
private:
float CalculateSimilarity(const FuncDecl& func, const ASTPattern& pattern) {
// 1. 函数签名匹配(参数类型和数量)
float signatureScore = MatchSignature(func, pattern);
// 2. 嵌套结构匹配(是否有双重循环)
float structureScore = MatchStructure(func.body, pattern.body);
// 3. 关键操作匹配(是否有比较、交换)
float operationScore = MatchOperations(func.body, pattern.body);
return signatureScore * 0.3f + structureScore * 0.4f + operationScore * 0.3f;
}
std::vector<Deviation> FindDeviations(const FuncDecl& func, const AlgorithmTemplate& tmpl) {
std::vector<Deviation> result;
// 检查每个常见错误模式
for (const auto& mistake : tmpl.commonMistakes) {
if (FindPattern(func.body, mistake.pattern)) {
result.push_back({
.type = mistake.name,
.message = mistake.message,
.fixSuggestion = mistake.fixSuggestion,
.studentCode = ExtractCode(func.body, mistake.pattern),
.correctCode = mistake.correct
});
}
}
return result;
}
};
1.3.3 算法修复的用户界面
┌──────────────────────────────────────────────┐
│ 🤔 算法诊断 [×] │
├──────────────────────────────────────────────┤
│ │
│ 我识别出你在实现「冒泡排序」。 │
│ │
│ 你的代码(第 3~8 行): │
│ ┌──────────────────────────────────────────┐ │
│ │ 3 │ for (int i = 0; i < n; i++) { │ │
│ │ │ ^^^^^^^ │ │
│ │ │ │ │ │
│ │ │ 📝 这里可能有问题 │ │
│ │ 4 │ for (int j = 0; j < n; j++) { │ │
│ │ │ ^^^^^ │ │
│ │ │ │ │ │
│ │ │ 📝 这里可能有问题 │ │
│ │ 5 │ if (arr[j] > arr[j+1]) { │ │
│ │ 6 │ // 交换... │ │
│ │ 7 │ } │ │
│ │ 8 │ } │ │
│ │ 9 │ } │ │
│ └──────────────────────────────────────────┘ │
│ │
│ 📊 运行时验证结果: │
│ 测试用例 [5, 3, 8, 1, 2] → 你的结果 [1, 2, 3, 5] │
│ ❌ 元素 8 丢失了! │
│ │
│ 🔍 问题分析: │
│ ┌──────────────────────────────────────────┐ │
│ │ 问题 1:外层循环边界过大 │ │
│ │ │ │
│ │ 你的写法:for (int i = 0; i < n; i++) │ │
│ │ 标准写法:for (int i = 0; i < n - 1; i++)│ │
│ │ │ │
│ │ 原因:冒泡排序只需 n-1 趟。因为每趟将一 │ │
│ │ 个最大元素"冒泡"到正确位置,n-1 趟 │ │
│ │ 后只剩最后一个元素,必然有序。 │ │
│ │ │ │
│ │ 💡 记忆口诀:外层 n-1,内层 n-i-1 │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ 问题 2:内层循环边界过大,导致越界访问 │ │
│ │ │ │
│ │ 你的写法:j < n │ │
│ │ 标准写法:j < n - i - 1 │ │
│ │ │ │
│ │ 原因:当 j = n-1 时,arr[j+1] = arr[n] │ │
│ │ 越界了!而且第 i 趟后最后 i 个元素 │ │
│ │ 已有序,不需要再比较。 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ [📖 查看标准模板] [🔧 应用修复] │
│ │
│ ⚠️ 注意:算法修复只是建议,建议你理解原因 │
│ 后再决定是否应用。 │
└──────────────────────────────────────────────┘
1.4 Level 2: 运行时验证(⚠️ 实现载体已随前端切割迁出,后端待重建)
1.4.1 Property-based Testing 实现
实现位置(2026-09-11 核对修正):本层的属性用例与判定逻辑原实现于前端载体(Dart 侧算法验证模型:AlgorithmTestCase / AlgorithmValidationResult + 手写用例),已随 2026-09-11 前端切割迁出,属历史资产(见标签 before-frontend-split)。原文所记 Rust 路径 native/src/engine/algorithm_validator.rs 与 validate_algorithm() 在本仓库中不存在(native/src/engine/ 现仅有 compile_pipeline.rs / session_ops.rs / completion/),此处按"诚实记录"更正。
后端现状(本仓库内已核实):
- 算法检测:
native/src/compiler/algorithm_detector/(detect_algorithms,由native/src/engine/compile_pipeline.rs写入会话)+AlgorithmMatch(native/src/session.rs:name/display_name/func_name/confidence/suggestion/line/vis_events); - 模板运行正确性回归:
native/tests/cases_template_generated/(模板生成用例,与 Clang golden 对照,属防线 1/2)——这是当前可用的替代验证路径; - 剩余缺口(诚实记录):替换学生
main()的测试桩生成、属性判定(长度守恒 / 非递减 / 元素守恒等)与失败用例明细,当前在本仓库没有实现;Level 2 能力随前端迁出,待社区前端或 wasm 出口认领,或按三出口载荷形状在后端重建。
原设计接口(示意,未在本仓库落地):
pub fn validate_algorithm(source: &str, match_info: &AlgorithmMatch) -> ValidationResult {
let test_cases = generate_test_cases(&match_info.name);
for tc in &test_cases {
let result = run_single_test(source, &match_info.func_name, &match_info.name, tc);
if !result.passed {
return result;
}
}
ValidationResult::passed(format!("{} 通过了 {} 组测试用例!", match_info.display_name, test_cases.len()))
}
测试桩生成(替换学生的 main()):
int main() {
int arr[] = {5, 3, 8, 1, 2};
int n = 5;
bubbleSort(arr, n);
for (int i = 0; i < n; i = i + 1) {
printf("%d ", arr[i]);
}
return 0;
}
支持的验证属性:
| 算法类型 | 属性 1 | 属性 2 | 属性 3 |
|---|---|---|---|
| 排序(8 种) | 输出长度 = 输入长度 | 非递减 | 元素守恒 |
| 二分查找 | 返回值为整数 | 目标存在时返回正确索引 | 目标不存在时返回 -1 |
| BFS/DFS | 访问节点数正确 | 无重复访问 | - |
| 链表操作 | 链表不断裂 | 头指针不为 NULL | - |
1.4.2 出口集成(后端能力 + 三出口载荷)
后端能力(本仓库已核实,语言中立层):
- 算法匹配与检测结果:
native/src/compiler/algorithm_detector/+AlgorithmMatch(native/src/session.rs),随编译诊断与运行结果一并返回; - 模板运行正确性回归:
native/tests/cases_template_generated/(Clang golden 对照); - 不含属性验证(见 §1.4.1 剩余缺口)——切割前该能力由前端载体提供,已迁出。
三出口载荷(消费方自行渲染,本仓库不再提供前端):
| 出口 | 消费方式 |
|---|---|
| capi(C ABI) | vitro_compile_json / vitro_run_json 等 JSON 字符串入口;复杂结构过边界一律 JSON(rust-alloc 所有权,vitro_free_string 释放) |
| wasm32 | 同一 C ABI 在浏览器/白盒形态下复用(冒烟已实证:零修改构建 + C API 全链路) |
vitro_cli serve |
JSON-lines(NDJSON)会话:compile / run / step.* / payload.get,见 CLI使用手册.md §6 |
历史记录:切割前算法 Tab 的"🔍 验证算法"按钮与结果 BottomSheet(绿色通过 / 红色失败 + 用例对比)由前端载体实现,已迁出(见标签
before-frontend-split);其判定逻辑属上述剩余缺口的一部分。
1.4.3 关键依赖:func_name 字段
pub struct AlgorithmMatch {
pub name: String,
pub func_name: String,
pub display_name: String,
pub suggestion: String,
}
1.5 Level 3: 执行轨迹分析
class TraceAnalyzer {
public:
// 记录每次 __vitro_step 时的状态
struct TraceEntry {
int step;
int line;
std::map<std::string, int> variables; // 变量当前值
std::vector<int> arrayState; // 数组当前状态
std::string operation; // "compare", "swap", "recurse"
};
std::vector<TraceEntry> trace;
void Analyze(const std::vector<TraceEntry>& trace,
const AlgorithmTemplate& tmpl) {
// 分析 1:比较次数是否正确?
int compareCount = CountOperations(trace, "compare");
int expectedCompareCount = tmpl.expectedCompareCount(trace[0].arrayState.size());
if (compareCount != expectedCompareCount) {
Report("比较次数异常:实际 %d 次,期望 %d 次",
compareCount, expectedCompareCount);
}
// 分析 2:是否有未比较的相邻元素?
auto unCompared = FindUncomparedPairs(trace);
if (!unCompared.empty()) {
Report("以下相邻元素未被比较:%s", FormatPairs(unCompared));
}
// 分析 3:递归深度是否合理?
int maxDepth = MaxRecursionDepth(trace);
if (maxDepth > trace[0].arrayState.size()) {
Report("递归深度 %d 超过数组大小 %d,可能存在无限递归",
maxDepth, trace[0].arrayState.size());
}
}
};
1.6 算法修复的分级与原则
┌─────────────────────────────────────────────────────────────┐
│ 算法修复分级 │
├─────────────────────────────────────────────────────────────┤
│ │
│ L1 语法/语义修复(全自动) │
│ ├── 数组越界、空指针、类型不匹配 │
│ └── 编译器直接发现,自动修复 │
│ │
│ L2 算法模式修复(建议 + 模板对比) │
│ ├── 识别算法类型 → 对比标准模板 → 发现边界/逻辑偏差 │
│ └── 展示「你的代码」vs「标准模板」,由学生决定是否修改 │
│ │
│ L3 运行时验证修复(诊断 + 测试用例) │
│ ├── 自动生成测试 → 发现结果错误 → 定位可疑区域 │
│ └── 提供测试失败信息和执行轨迹,引导学生自查 │
│ │
│ L4 逻辑漏洞修复(仅提示,不修复) │
│ ├── 递归缺少终止条件、算法逻辑根本性错误 │
│ └── 仅提供教学提示,不自动修改代码(保护思考过程) │
│ │
└─────────────────────────────────────────────────────────────┘
核心原则:算法修复的目的是教懂学生,不是代写代码。L2/L3/L4 级别永远不自动应用,只提供分析和引导。
2. C 子集扩展路线图
2.1 四级扩展策略
Phase 1: 核心子集(教学入门)
├── 数据类型:int, int*, int[], struct
├── 控制流:if/else, while, for
├── 函数:定义/调用/递归
├── 内存:malloc/free(简化版)
└── 内置:print_int, print_array
Phase 2: 数据结构基础(解锁条件:完成链表练习)
├── + break/continue
├── + sizeof(简化版,固定返回 4)
├── + 字符串字面量("hello",仅用于输出)
└── + vis_* 可视化内置函数
Phase 3: 进阶语法(解锁条件:完成树/图练习)
├── + 多维数组(int arr[3][4])
├── + typedef(struct 别名)
├── + 枚举 enum
└── + 函数指针(简化版,用于 qsort)
Phase 4: 实用编程(解锁条件:完成综合项目)
├── + 字符串操作(strlen, strcpy, strcmp 简化版)
├── + 数学函数(abs, min, max)
├── + 文件 I/O(沙盒内虚拟文件系统)
└── + 标准库子集
2.2 渐进式解锁机制
// 用户学习进度追踪
public class LearningProgress {
public int Level { get; set; } = 1;
public HashSet<string> CompletedExercises { get; set; } = new();
public HashSet<string> UnlockedFeatures { get; set; } = new();
// 检查特性是否可用
public bool CanUse(string feature) => feature switch {
"break" => Level >= 2,
"multi_array" => Level >= 3,
"string_ops" => Level >= 4,
"file_io" => Level >= 4,
_ => true // Phase 1 特性默认可用
};
// 完成练习后解锁新特性
public void CompleteExercise(string exerciseId) {
CompletedExercises.Add(exerciseId);
// 完成链表练习 → 解锁 break/continue
if (exerciseId == "linked_list_basics" && !UnlockedFeatures.Contains("break")) {
UnlockedFeatures.Add("break");
UnlockedFeatures.Add("continue");
NotifyUser("🎉 解锁新语法:break / continue!");
}
// 完成树练习 → 解锁多维数组
if (exerciseId == "binary_tree_traversal" && !UnlockedFeatures.Contains("multi_array")) {
UnlockedFeatures.Add("multi_array");
NotifyUser("🎉 解锁新语法:多维数组!");
}
}
}
// 编译器根据用户等级决定是否支持语法
public class ProgressiveCompiler {
public CompileResult Compile(string source, LearningProgress progress) {
var lexer = new Lexer(source, progress); // 传入进度
var tokens = lexer.Tokenize();
// 如果用户还没解锁 break,遇到 break 时报特殊错误
if (!progress.CanUse("break") && tokens.Any(t => t.Type == TokenType.BREAK)) {
return CompileResult.Error(
"break 语句将在「数据结构篇」解锁。\n" +
"当前请使用 return 或调整循环条件。\n\n" +
"💡 完成「链表基础」练习后即可解锁!"
);
}
// ... 正常编译
}
}
2.3 向后兼容性保证
Phase 1 代码
↓
Phase 2 编译器(完全兼容)
↓
Phase 3 编译器(完全兼容)
↓
Phase 4 编译器(完全兼容)
所有旧代码在新版本中都能正常运行。
只增加语法,不修改已有语法语义。
3. 数据结构教学支持
3.1 当前子集支持的数据结构
载体口径(2026-09-27 注):下表与本节 §3.2 的
vis_array()/vis_list()等vis_*内置函数属设计稿形态,后端从未实现(native/src全量零命中)——现役等价物是引擎自动产出的vis_events协议载荷(零侵入检测,AlgorithmMatch/ StepPayload 帧内承载),渲染由下游完成。本节保留为设计意图与缺口论证的原始口径。
| 数据结构 | 实现方式 | 可视化支持 | 诊断支持 |
|---|---|---|---|
| 数组 | 原生 int[] |
vis_array() |
越界检测 |
| 动态数组 | malloc + 指针 |
vis_array() + 内存视图 |
泄漏检测 |
| 单链表 | struct Node { int val; Node* next; } |
vis_list() |
断链检测、泄漏检测 |
| 双链表 | struct DNode { int val; DNode* prev; DNode* next; } |
vis_list() |
断链检测 |
| 栈(数组) | int[] + top 索引 |
vis_stack() |
上溢/下溢检测 |
| 栈(链表) | 链表 | vis_stack() |
断链检测 |
| 队列(数组) | 循环数组 | vis_queue() |
上溢/下溢检测 |
| 队列(链表) | 链表 + head/tail | vis_queue() |
断链检测 |
| 二叉树 | struct TreeNode { int val; TreeNode* left; TreeNode* right; } |
vis_tree() |
递归深度检测 |
| 图(邻接矩阵) | 二维数组(Phase 3) | vis_graph() |
- |
| 图(邻接表) | 数组 + 链表混合 | vis_graph() |
- |
3.2 数据结构专用内置函数
// ===== 数组可视化 =====
void vis_array(const char* name, int arr[], int n);
void vis_array_highlight(const char* name, int index, const char* color);
// color: "compare"(橙), "swap"(粉), "sorted"(绿), "active"(蓝)
void vis_array_range(const char* name, int begin, int end, const char* color);
// 高亮一个区间,如 vis_array_range("arr", 2, 5, "range");
// ===== 链表可视化 =====
void vis_list_node(int id, int value, int nextId);
void vis_list_highlight(int id, const char* color);
void vis_list_edge(int fromId, int toId);
void vis_list_pointer(const char* name, int nodeId);
// 显示头指针/尾指针指向
// ===== 树可视化 =====
void vis_tree_node(int id, int value, int leftId, int rightId);
void vis_tree_highlight(int id, const char* color);
void vis_tree_edge(int fromId, int toId);
// ===== 栈/队列可视化 =====
void vis_stack_push(const char* name, int value);
void vis_stack_pop(const char* name);
void vis_stack_highlight(const char* name, int index, const char* color);
void vis_queue_enqueue(const char* name, int value);
void vis_queue_dequeue(const char* name);
// ===== 图可视化(Phase 3)=====
void vis_graph_node(int id, int value);
void vis_graph_edge(int fromId, int toId, int weight);
void vis_graph_highlight_node(int id, const char* color);
void vis_graph_highlight_edge(int fromId, int toId, const char* color);
// ===== 通用调试 =====
void vis_step(int line); // 高亮当前执行行
void vis_variable(const char* name, int value);
void vis_pointer(const char* name, void* ptr);
void vis_message(const char* text); // 显示文字消息
3.3 数据结构专用的诊断和修复
3.3.1 链表断链检测
// 学生代码:危险的链表操作
void deleteNode(struct ListNode* head, int val) {
struct ListNode* p = head;
while (p != NULL) {
if (p->val == val) {
p = p->next; // ❌ 直接移动,丢失被删除节点的前驱
free(p); // ❌ 先移动再 free,free 的是下一个节点!
}
p = p->next;
}
}
运行时诊断:
⚠️ 链表操作警告(第 6~7 行)
你的操作顺序可能导致链表断裂或错误释放内存。
执行轨迹:
step 5: p 指向 node1(val=3)
step 6: p = p->next → p 现在指向 node2
step 7: free(p) → 释放了 node2!但 node1->next 还指向 node2!
🔴 问题:
1. 你先移动了 p,再 free(p),结果 free 的是下一个节点
2. node1->next 变成了悬垂指针
✅ 正确顺序:
struct ListNode* temp = p->next; // 先保存下一个节点
p->next = temp->next; // 跳过要删除的节点
free(temp); // 再释放
📚 [链表删除操作详解]
3.3.2 内存泄漏检测(链表)
// 学生代码:忘记释放链表
struct ListNode* createList(int n) {
struct ListNode* head = NULL;
for (int i = 0; i < n; i++) {
struct ListNode* node = malloc(sizeof(struct ListNode));
node->val = i;
node->next = head;
head = node;
}
return head; // ❌ 函数结束时没有释放链表
}
程序结束时的内存诊断:
⚠️ 内存泄漏检测
程序结束时,以下内存未被释放:
地址 大小 分配位置 类型
0x1000 8 字节 createList 第 5 行 struct ListNode
0x1008 8 字节 createList 第 5 行 struct ListNode
0x1010 8 字节 createList 第 5 行 struct ListNode
...(共 5 个节点)
💡 建议:在程序结束前遍历链表,逐个 free:
while (head != NULL) {
struct ListNode* temp = head;
head = head->next;
free(temp);
}
📚 [什么是内存泄漏?] [如何正确释放链表?]
3.3.3 递归深度检测(树遍历)
// 学生代码:缺少终止条件检查
void preorder(struct TreeNode* root) {
// ❌ 忘记检查 root == NULL
vis_tree_highlight(root->id, "active");
printf("%d ", root->val);
preorder(root->left);
preorder(root->right);
}
运行时检测:
😵 栈溢出(递归深度超过 1000)
递归函数 preorder 在第 3 行被无限调用。
执行轨迹:
call 1: root = node1
call 2: root = node1->left = NULL
call 3: root = NULL->left = ??? ← 崩溃!
🔴 问题:你没有检查 root 是否为 NULL 就访问了 root->left。
✅ 修复:
void preorder(struct TreeNode* root) {
if (root == NULL) return; ← 添加终止条件
// ...
}
💡 记忆口诀:递归函数第一行,先写终止条件!
3.4 代码模板库(88 个内置模板:82 C + 6 C++,C++ 线随砍 C++ 裁定冻结于 oracle)
排序算法(9)
- 冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序、希尔排序、计数排序、基数排序
查找算法(2)
- 线性查找、二分查找
图算法(7)
- BFS 广度优先搜索、DFS 深度优先搜索
- Prim 最小生成树、Kruskal 最小生成树
- Dijkstra 最短路径、Floyd 最短路径
- 拓扑排序
动态规划(2)
- 斐波那契数列、01 背包
数据结构(22)
- 顺序表、链表节点/头插/尾插/遍历/删除/双向链表/循环链表/静态链表
- 二叉树节点/先序/中序/后序/层序遍历、BST 插入与查找、线索二叉树、哈夫曼树、AVL 树
- 链栈、链队列、循环队列、哈希表(线性探测)、并查集
字符串(3)
- 字符串反转、朴素模式匹配(BF)、KMP 模式匹配
基础/递归(7)
- 数组遍历、指针交换两数、GCD 欧几里得、素数判断、约瑟夫环
- 阶乘、递归斐波那契、汉诺塔
每个模板均支持:
- 参数化占位符:
/*__PARAM_n__*/ 5形态(现行唯一语法,见模板维护指南.md §3;切割前旧 Dart 语法{{n:5}}已移除,参数收集 UI 属前端载体) - 交互式教程:逐步骤高亮代码行,关键行可展开中文解释(教程渲染属前端载体)
- 自动编译运行:教程最后一步自动插入生成代码、编译并启动统一模式
- 算法步骤语义标注:运行时根据源码行特征和变量值推断当前阶段,生成中文教学描述
载体说明(2026-09-11):切割前上述"参数收集弹窗 / 教程面板 / 自动编译运行"由前端组件实现,已随前端切割迁出(历史资产,见标签
before-frontend-split)。本仓库现只保留模板源templates/<key>/(source.c+meta.yaml)与后端语义标注能力;模板源的归属见CHANGELOG.md[Unreleased]Removed 段(暂保留待社区前端或 wasm 出口认领)。
4. 知识图谱:从语法到算法到数据结构
知识图谱
│
├─ 基础语法
│ ├─ 变量与类型 → int, 内存中的表示
│ ├─ 表达式 → 运算符优先级
│ ├─ 控制流 → if/else, for, while
│ └─ 函数 → 参数传递, 递归
│
├─ 内存与指针(解锁条件:掌握基础语法)
│ ├─ 数组 → 连续内存, 索引计算
│ ├─ 指针 → &取地址, *解引用, NULL
│ ├─ 栈与堆 → 局部变量, malloc/free
│ └─ 常见错误 → 越界, 空指针, 悬垂指针, 泄漏
│
├─ 数据结构基础(解锁条件:掌握指针)
│ ├─ 链表 → 单链表, 双链表, 插入, 删除, 遍历
│ ├─ 栈 → 数组实现, 链表实现, 应用
│ ├─ 队列 → 循环数组, 链表实现, 应用
│ └─ 树 → 二叉树, 遍历(前/中/后/层序), BST
│
├─ 算法基础(解锁条件:掌握数组和循环)
│ ├─ 排序 → 冒泡, 选择, 插入, 快排, 归并
│ ├─ 搜索 → 线性, 二分
│ └─ 递归 → 阶乘, 斐波那契, 树遍历
│
└─ 进阶数据结构(解锁条件:掌握基础数据结构)
├─ 图 → 邻接矩阵, 邻接表, BFS, DFS
├─ 高级树 → AVL, 红黑树(概念)
└─ 哈希表 → 概念, 冲突处理
每个知识点关联:
- 错误码(数组越界 → 数组知识卡片)
- 练习题(完成练习解锁下一个知识点)
- 可视化演示(数组排序动画、链表操作动画)
5. 实施优先级
Phase 1:核心子集 + 基础修复(✅ 已完成)
- C 子集编译器(int, float, double, long long, 数组, 指针, struct, union, enum, typedef, if/for/while/do-while/switch, 函数, malloc/free/realloc)
- 基础修复(语法错误、数组越界、空指针、未初始化)
- 内存视图 + 指针视图 + 堆内存可视化
- 结构化诊断系统(错误码 + 知识卡片 + 自动修复建议)
- 基础算法模板(冒泡排序、二分查找)
Phase 2:算法修复 + 数据结构基础(✅ 已完成)
- 算法模式识别系统(17+ 种算法/数据结构检测)
- 算法步骤语义标注(27 种算法/数据结构操作预定义步骤模板)
- 运行时验证(Property-based Testing)— ⚠️ 载体为前端,已随前端切割迁出(后端无对应模块,见 §1.4.1 诚实记录)
- 执行轨迹分析(TraceAnalyzer -> RootCauseHint)
- 代码模板参数化 + 交互式教程(57 个模板)— 模板源现保留在
templates/<key>/,教程渲染属前端载体(已迁出) - 链表、栈、队列、二叉树可视化(CustomPainter)— ⚠️ 渲染层为前端载体,已迁出;后端保留可视化事件载荷(
vis_events) - 数据结构专用诊断(断链检测、泄漏检测、Use-After-Free/Double-Free 运行时检测)
Phase 3:进阶扩展(✅ 已完成 / 🔄 进行中)
- 更多算法模板(快排、归并、堆排序、希尔排序、计数排序)
- 图算法模板(BFS、DFS)
- 多维数组
- 知识图谱系统(24 概念节点 + 30+ 关系边)
- 用户学习进度追踪(LearningProgress + SharedPreferences 持久化)— ⚠️ 进度状态与持久化均为前端载体,已随前端切割迁出;后端保留推荐引擎
native/src/diagnostics/learning_path.rs(LearningPath/PathStep/recommend_learning_paths),进度状态需由消费方自行持有 - 认知推理 P0~P3(根因分析 -> 教学推理 -> 知识图谱 -> 代码理解/意图推断)
- 语义智能补全 v2(5 种上下文感知补全)
- 模板 JIT 加速(Trace-based Loop Accelerator)
- Dijkstra 算法模板(
templates/dijkstra/,已进标注 golden) - 社区贡献的算法模板
Phase 4:完整生态(后续)
- 字符串操作(strlen, strcpy, strcmp, strcat)
- 文件 I/O(fopen, fclose, fgets, fputs, fread, fwrite)
- 更多标准库函数(qsort, fprintf, atoi, putchar, srand/rand, memset)
-
OCR 照片导入— 已随前端切割作废(相机/图库权限与图像输入属前端能力,本仓库为纯后端且已放弃原生移动端) - 在线判题(OJ)集成 — 保留(headless 判分可由三出口承载:capi /
vitro_cli serve/ wasm32)
6. 总结
算法层面的错误能修复吗?
不能直接"自动修复",但可以"智能诊断 + 引导修复"。
| 层级 | 能力 | 方式 |
|---|---|---|
| 语法/语义 | 自动修复 | 编译器直接发现和修复 |
| 算法模式 | 模板对比 + 建议 | "你的冒泡排序边界应该是 n-1" |
| 运行时验证 | 测试驱动诊断 | "排序结果不正确,元素 8 丢失了" |
| 执行轨迹 | 轨迹分析 | "第 3 趟没有比较 arr[2] 和 arr[3]" |
| 逻辑漏洞 | 仅提示 | "递归函数缺少终止条件检查" |
核心原则:算法修复不是代写代码,而是帮助学生理解算法逻辑。
如何支持数据结构?
当前子集(int + 指针 + struct + malloc)已经支持链表、树、栈、队列的全部基础操作。
需要补充:
- 内置可视化函数(
vis_list,vis_tree,vis_stack) - 数据结构专用诊断(断链检测、泄漏检测、递归深度)
- Starter Code 模板(ListNode, TreeNode, 辅助函数)
- 逐步解锁机制(完成链表练习后解锁 break/continue 和树的相关内容)
子集扩展的关键
不是一次性做大,而是按需渐进式扩展:
- Phase 1 足够支持排序、搜索、递归
- Phase 2 解锁 break/continue 后支持更复杂的链表操作
- Phase 3 解锁多维数组后支持图的邻接矩阵
- 每个新特性都有明确的学习路径和解锁条件
7. 本次翻新发现的实现缺口(2026-09-11)
本节为 2026-09-11 文档翻新(去前端化 + 失效引用修复)过程中核实到的文档与实现不一致项,按"诚实记录"原则集中列出。结论均有本仓库实际代码 / git 证据支撑;本次翻新只做文档记录,不新增或修改任何
.rs代码。
| # | 缺口 | 原文(翻新前)表述 | 核实结果 | 证据 |
|---|---|---|---|---|
| 1 | 运行时算法属性验证(Level 2) | §1.4 记"✅ 已实现",实现位置 native/src/engine/algorithm_validator.rs(Rust 后端)+ 前端 |
Rust 后端无实现:validate_algorithm() / ValidationResult 在 native/ 下无任何定义(整目录检索零命中);native/src/engine/ 现仅有 compile_pipeline.rs / session_ops.rs / completion/。实际载体是前端侧算法验证模型(AlgorithmTestCase / AlgorithmValidationResult + 手写属性用例),已随前端切割迁出 |
git log --all -S "validate_algorithm" 仅 1 个提交 a29a056;历史中唯一相关路径为 CideFlutter/lib/models/algorithm_validation.dart(历史资产,已迁出)——标签 before-frontend-split 中存在,HEAD 已无 |
| 2 | 学习进度追踪 | Phase 3 记"用户学习进度追踪(LearningProgress + SharedPreferences 持久化)"已实现 |
后端无 LearningProgress(native/src 零命中);后端只提供推荐引擎 native/src/diagnostics/learning_path.rs(LearningPath / PathStep / recommend_learning_paths)。进度状态与持久化原为前端载体,已迁出(历史资产,已迁出) |
native/src 检索 LearningProgress 零命中;learning_path.rs 实际导出如上 |
| 3 | AlgorithmMatch 的归属(澄清,非缺口) |
§1.4.1 / §1.4.3 将该结构体与"验证"绑定 | AlgorithmMatch 在 Rust 确实存在(native/src/session.rs),但它是算法检测结果(name / display_name / func_name / confidence / suggestion / line / vis_events),不含任何验证逻辑;检测实现为 native/src/compiler/algorithm_detector/,经 compile_pipeline 写入会话 |
见 §1.4.1 / §1.4.2 已更正的正文 |
| 4 | 模板参数替换与教程渲染 API | 本文 §3.4 与 ARCHIVE_数据结构模板路线图.md §7 记 buildCode() / focusLines / LineExplanation 为验收项 |
均为前端载体 API,已迁出;本仓库现只保留模板源 templates/<key>/(source.c + meta.yaml),加载 / 参数替换 / 教程渲染代码、scripts/test_templates.py 均已移除;scripts/sync_templates.py 已于 2026-09-12(R4 G1)恢复后端职能 |
CHANGELOG.md [Unreleased] Removed 段 |
当前可用的替代验证路径(后端,已核实):
- 算法检测:
native/src/compiler/algorithm_detector/(detect_algorithms,由native/src/engine/compile_pipeline.rs调用); - 模板运行正确性:
native/tests/cases_template_generated/的模板生成用例(与 Clang golden 对照,属 Shadow 防线); - 算法步骤语义标注:
native/crates/vitro_algorithm_steps/(27 种算法预定义步骤模板)。
结论:缺口 1、2 属"能力原本只在前端载体、后端从未落地",前端切割后在本仓库为无实现状态;需由维护者决策是后端重建(按三出口 JSON 载荷形状)还是随模板源一并交社区前端认领。
补记(2026-09-13):
- 缺口 4 中
scripts/sync_templates.py已由重构批次 R4 G1 于 2026-09-12 从历史提交恢复(纯后端形态:渲染模板源 + Clang Golden,见模板维护指南.md§4.2);test_templates.py仍未恢复。- 缺口 1(运行时算法属性验证,即项目路线图 G9)的重建排期锚定在 C# 主线 CS5(见 CSharp前端引入计划.md;缺口 2(学习进度追踪)维持"进度状态由消费方持有"口径。