A WebAssembly practice project: a pure front-end English–Chinese dictionary comparing BST, AVL and sequential search performance — Rust compiled to WebAssembly, running entirely in the browser.
Rust + WebAssembly 练习项目:纯前端英汉词典,核心逻辑(BST / AVL / 顺序搜索 三种数据结构)由 Rust 编译为 WebAssembly,在浏览器中运行并实时对比查询性能。
本项目为中国地质大学《数据结构》课程作业,同时是一个 Rust + WebAssembly(wasm)练习项目:用 Rust 编写核心算法并编译为 wasm 在浏览器中直接执行,实践 "Rust → wasm-pack → wasm-bindgen → 浏览器" 的完整链路。
- wasm 练习目标:Rust 源码经 wasm-pack 编译为
.wasm二进制,通过 wasm-bindgen 将 API 暴露给 JavaScript 调用;CSV 解析、三种结构构建与查询 全部在浏览器本地由 wasm 完成(纯前端,无后端、无外部网络请求) - 数据结构目标:以同一份英汉词典数据(103,976 词条)实现并对比三种 查找结构——二叉搜索树(BST)、AVL 自平衡树、顺序表线性查找, 实时展示每种结构的比较次数、比较路径与耗时,直观呈现 对数级(O(log n))与线性级(O(n))的差距
- 覆盖教材核心知识点:二叉搜索树的退化问题(有序数据插入会退化成链状结构, 导致栈溢出与 O(n) 查询)、AVL 树的旋转再平衡、顺序查找的提前终止优化
- 工程化要求:单元测试 + 集成测试 + 真实数据回归、GitHub Actions CI、 中英双语响应式前端界面
全程本地运行,无需联网。预期数据为实测值,允许 ±2 内波动。
PowerShell 中确认均有版本输出:
rustc --version # 例如 rustc 1.89.0
cargo --version
wasm-pack --version # 例如 wasm-pack 0.13.1未安装 wasm-pack:
cargo install wasm-pack;scripts\build_wasm.bat也会自动安装。
Windows:双击 scripts\build_wasm.bat(等价命令:
wasm-pack build --target web --release)
预期末尾输出:[INFO]: :-) Your wasm pkg is ready to publish at ...\pkg
双击 scripts\serve_web.bat,浏览器打开 http://127.0.0.1:8080
Linux/macOS:
./build.sh构建、scripts/serve_web.sh启动。
页面加载后状态徽章变为 "Dictionary loaded · 词典加载完成" (10.4 万词条约 0.3~1 秒)。
三个统计卡片 Entries 词条 均显示 103,976。
搜索框中输入单词(回车或 Search):
- 左栏:显示单词与唯一释义;下方三个徽章均为
✓ 命中 - 右栏:三张路径卡片(绿色左边框),步数差异巨大:
| 单词 | BST 步数 | 顺序搜索步数 | 说明 |
|---|---|---|---|
a |
≈17 | 1 | 顺序表排在最前,1 步即中 |
apple |
≈16 | 5,077 | 位置靠前 |
hello |
≈16 | 41,528 | 位置居中 |
world |
≈16 | 102,616 | 位置靠后 |
zebra |
≈17 | 103,554 | 接近末尾 |
| 单词 | 左栏 | 徽章 | BST 步数 | 顺序搜索步数 |
|---|---|---|---|---|
aa |
红色"未找到" | 三个 ✗ |
≈17 | 2(遇到 a 提前终止) |
zzzzzz |
红色"未找到" | 三个 ✗ |
≈16 | 103,976(扫完全表) |
zzzzzz 的路径只显示前 50 步 + …,标题行仍标注真实步数 103,976。
每次搜索后三个卡片 Time 用时 更新(自动换算 ns/µs/ms),
最快结构的统计卡片呈绿色边框 + 绿色背景(通常 BST 或 AVL)。
- 输入
hel→ 弹出以 hel 开头的建议列表(已输入前缀加粗显示) - 点击建议词 → 回填搜索框并立即搜索
↓/↑移动选中项、Enter选中搜索、Esc关闭
输入停止约 0.3 秒后才自动触发搜索(快速连续输入不会逐字搜索)。
- 跟随系统深色/浅色主题自动切换
- 窗口 <760px 时左右两栏纵向堆叠;<640px 时统计卡片纵向堆叠
- 将
data目录临时改名(如data_bak),刷新页面 - 加载失败后自动使用内置 30 词备用数据,页面仍可完整测试
- 测完改回
data再刷新即可恢复全量数据
F12 执行(复用已加载的 wasm 模块,新建独立实例演示):
import('./pkg/dictionary_wasm.js').then(({ default: init, DictionaryManager }) =>
init().then(() => {
const m = new DictionaryManager();
m.load_from_csv('hello,你好\nworld,世界');
console.log(m.get_stats()); // {bst_size:2, avl_size:2, sequential_size:2}
console.log(m.get_suggestions('he', 10)); // ["hello"]
})
);cargo test # 32 个测试全绿(27 单元 + 3 集成 + 2 真实数据)
cargo clippy --all-targets -- -D warnings # 零告警
cargo fmt --all -- --check # 格式一致真实数据回归测试加载完整 10.4 万词条,断言三结构查询结果一致、size 一致、 BST 未命中 ≤30 步 vs 顺序搜索 >50,000 步。
同一份词典数据被载入三种结构,每次查询同时执行并对比:
| 结构 | 插入 | 查询 | 10.4 万词条时预期比较次数 |
|---|---|---|---|
| BST | O(log n) 平均 | O(log n) 平均 | ~17 |
| AVL | O(log n) | O(log n) 最坏 | ~17 |
| Sequential | O(n) | O(n) | 最多 103,976 |
词典数据本身按字母序排列:朴素的递归 BST 会退化成 10 万层链表(栈溢出风险)。 本项目采用迭代插入/搜索(不依赖尾调用优化)+ 载入时批量平衡建树; 顺序表同样保持有序,扫描可提前终止——对比公平且差距依然鲜明。
├── data/dictionary.csv # 103,976 英汉词条(UTF-8,带引号 CSV,释义含逗号)
├── src/
│ ├── lib.rs # wasm-bindgen API(DictionaryManager)
│ ├── csv.rs # 无依赖 RFC4180 CSV 解析器
│ ├── models.rs # 共享类型 + Dictionary trait
│ ├── bst.rs # BST(迭代插入/搜索,批量平衡建树)
│ ├── avl.rs # AVL 自平衡树
│ └── sequential.rs # 有序向量线性扫描(演示基线)
├── tests/
│ ├── integration.rs # 三结构一致性
│ └── real_data.rs # 真实词典回归
├── index.html # 全部前端(无框架、无构建步骤)
├── pkg/ # wasm-pack 输出(自动生成,不入库)
├── scripts/ # Windows/Linux 构建与启动脚本
└── .github/workflows/ci.yml # CI:fmt/clippy/test + wasm 构建 + Pages 部署
push 到 main 后 GitHub Actions 自动:跑测试 → 构建 wasm → 组装
index.html + data/ + pkg/ 并部署到 GitHub Pages。
首次使用需在仓库 Settings → Pages → Source 选择 GitHub Actions。
data/dictionary.csv 为本地词典合集导出的 103,976 条英汉词条(UTF-8)。
如需在个人/教育用途之外使用,请先核实数据许可。
MIT 或 Apache-2.0 双许可(任选其一):见 LICENSE_MIT / LICENSE_APACHE。
Rust and WebAssembly Working Group 与 wasm-pack 提供的工具链。