# hellods
**Repository Path**: chobity/hellods
## Basic Information
- **Project Name**: hellods
- **Description**: C++ 实现的完整、通用的基础数据结构模板库
- **Primary Language**: C++
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 4
- **Forks**: 1
- **Created**: 2023-01-01
- **Last Updated**: 2026-06-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# HelloDS
_C++ 实现的基础数据结构模板代码库_
> 优雅,实在是太优雅了!
## 1. 基本属性
- 名称:HelloDS,意为 **Hello** **D**ata **S**tructure
- 语言:C++,满足 C++23 标准
- 目标:实现一套便于学习、收藏、展示的基础数据结构模板代码;不使用任何标准库容器;支持迭代器
- 模块:List, Stack, Queue, Deque, Heap, Tree, Graph, Set, Map, DisjointSet
- 简洁:Stay simple, stay young. 在保证健壮的前提下,尽量简洁,便于维护和阅读
- 健壮:安全的扩容机制,防止溢出。对容器的增删改查都有相应的检查
- 风格:大部分遵循 [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) ,小部分基于项目规模和源码简洁性的考虑采用自己的风格
- 测试:使用 [Catch2](https://github.com/catchorg/Catch2) 进行了测试,确保测试全部通过
- 安全:使用 [Dr. Memory](https://drmemory.org) 进行了检查,确保没有安全问题
- 文档:使用 [Doxygen](https://www.doxygen.nl) 生成文档
- 构建:使用 [XMake](https://xmake.io) 进行构建
### 项目亮点
- 零标准库容器依赖:全部容器和迭代器均从零实现,展示完整的实现思路与细节
- 统一的迭代器体系:基于 Concept + Model 实现类型擦除迭代器,全容器统一迭代器接口
- 完备的生命周期:所有容器均实现了 Rule of Five,资源管理安全可靠
### 模块一览
```mermaid
graph TD
subgraph 线性["线性容器"]
List --> ArrayList & LinkedList & SinglyLinkedList
Stack --> ArrayStack & LinkedStack
Queue --> ArrayQueue & LinkedQueue
Deque --> ArrayDeque & LinkedDeque
end
subgraph 树形["树形容器"]
Tree --> BinarySearchTree & AVLTree & RedBlackTree & SplayTree
end
subgraph 图形["图容器"]
Graph --> MatrixGraph & ListGraph
end
subgraph 堆["堆容器"]
Heap --> BinaryHeap & PairingHeap & SkewHeap
end
subgraph 集合["集合容器"]
Set --> HashSet & TreeSet
Map --> HashMap & TreeMap
end
subgraph 划分["划分结构"]
DisjointSet --> UnionFind
end
```
### 核心特性
| 容器 | 底层结构 | 特征 | 亮点 |
| ------------------ | -------- | ------------------------------- | ------------------------ |
| `ArrayList` | 动态数组 | 随机访问 O(1),尾部追加快 | - |
| `LinkedList` | 双向链表 | 插入删除节点高效 | 缓存实现访问加速 |
| `SinglyLinkedList` | 单向链表 | 内存占用低,仅支持正向遍历 | - |
| `ArrayStack` | 动态数组 | LIFO,尾部 push/pop 高效 | - |
| `LinkedStack` | 双向链表 | LIFO,适合频繁动态扩缩容 | - |
| `ArrayQueue` | 循环数组 | FIFO,环形缓冲区 | - |
| `LinkedQueue` | 双向链表 | FIFO,适合频繁动态扩缩容 | - |
| `ArrayDeque` | 循环数组 | 头尾操作均为 O(1) 摊还 | 迭代器自动处理环形绕回 |
| `LinkedDeque` | 双向链表 | 头尾插删高效 | - |
| `BinaryHeap` | 动态数组 | 堆顶访问高效,适合优先级场景 | 模板支持大顶堆和小顶堆 |
| `PairingHeap` | 多叉树 | 支持 O(1) 摊还插入 | 基于 meld 操作,实现极简 |
| `SkewHeap` | 二叉树 | 自调整结构,不存额外平衡信息 | 代码最精简的 meld 堆 |
| `BinarySearchTree` | 二叉树 | 中序遍历有序,查找平均 O(log N) | 虚拟最大节点简化双向迭代 |
| `AVLTree` | 二叉树 | 严格平衡,查找性能稳定 | - |
| `RedBlackTree` | 二叉树 | 近似平衡,更新操作代价低 | - |
| `SplayTree` | 二叉树 | 访问热点会被逐步伸展到上层 | - |
| `MatrixGraph` | 邻接矩阵 | 稠密图友好,边查询 O(1) | - |
| `ListGraph` | 邻接表 | 稀疏图友好,适合遍历邻边 | - |
| `HashSet` | 散列表 | O(1) 查找,无重复元素 | - |
| `TreeSet` | 二叉树 | 元素有序,支持范围相关操作 | - |
| `HashMap` | 散列表 | O(1) 键查找与更新 | 正负交替二次探测缓解聚集 |
| `TreeMap` | 二叉树 | 键有序,支持有序映射操作 | - |
| `UnionFind` | 树形数组 | 路径压缩 + 按秩合并 O(α(N)) | 模板支持任意类型 |
### 时间复杂度
**List**
| | `operator[]` | `append` | `insert` | `remove` |
| ------------------ | ---------------- | --------- | -------- | -------- |
| `ArrayList` | O(1) | O(1) 摊还 | O(N) | O(N) |
| `LinkedList` | O(N)† | O(1) | O(N) | O(N) |
| `SinglyLinkedList` | O(N) | O(1) | O(N) | O(N) |
† 带最近访问缓存,时间局部性好时接近 O(1)
**Stack**
| | `push` | `pop` | `top` |
| ------------- | --------- | ----- | ----- |
| `ArrayStack` | O(1) 摊还 | O(1) | O(1) |
| `LinkedStack` | O(1) | O(1) | O(1) |
**Queue**
| | `enqueue` | `dequeue` | `front` |
| ------------- | --------- | --------- | ------- |
| `ArrayQueue` | O(1) 摊还 | O(1) | O(1) |
| `LinkedQueue` | O(1) | O(1) | O(1) |
**Deque**
| | `push_front` | `push_back` | `pop_front` | `pop_back` |
| ------------- | ------------ | ----------- | ----------- | ---------- |
| `ArrayDeque` | O(1) 摊还 | O(1) 摊还 | O(1) | O(1) |
| `LinkedDeque` | O(1) | O(1) | O(1) | O(1) |
**Heap**
| | `peek` | `push` | `pop` | `meld` |
| ------------- | ------ | ------------- | ------------- | ------------- |
| `BinaryHeap` | O(1) | O(log N) | O(log N) | O(N log N) |
| `PairingHeap` | O(1) | O(1) 摊还 | O(log N) 摊还 | O(1) |
| `SkewHeap` | O(1) | O(log N) 摊还 | O(log N) 摊还 | O(log N) 摊还 |
**Tree**
| | `find` | `insert` | `remove` |
| ------------------ | ------------- | ------------- | ------------- |
| `BinarySearchTree` | O(log N) 平均 | O(log N) 平均 | O(log N) 平均 |
| `AVLTree` | O(log N) | O(log N) | O(log N) |
| `RedBlackTree` | O(log N) | O(log N) | O(log N) |
| `SplayTree` | O(log N) 摊还 | O(log N) 摊还 | O(log N) 摊还 |
**Set**
| | `find` | `insert` | `remove` |
| --------- | --------- | --------- | --------- |
| `HashSet` | O(1) 平均 | O(1) 平均 | O(1) 平均 |
| `TreeSet` | O(log N) | O(log N) | O(log N) |
**Map**
| | `find` | `insert` | `remove` | `operator[]` |
| --------- | --------- | --------- | --------- | ------------ |
| `HashMap` | O(1) 平均 | O(1) 平均 | O(1) 平均 | O(1) 平均 |
| `TreeMap` | O(log N) | O(log N) | O(log N) | O(log N) |
**Graph**
| | `link` / `unlink` | `distance` | DFS / BFS | `dijkstra` |
| ------------- | ----------------- | ---------- | ---------------- | ---------------- |
| `MatrixGraph` | O(1) | O(1) | O(V2) | O(V2) |
| `ListGraph` | O(V) | O(V) | O(V + E) | O((V + E) log V) |
**DisjointSet**
| | `find` | `unite` | `is_connected` |
| ----------- | ------- | ------- | -------------- |
| `UnionFind` | O(α(N)) | O(α(N)) | O(α(N)) |
说明:
记号:`N` 表示输入数据规模,图论中 `V` 表示顶点数,`E` 表示边数。
摊还:单次操作可能较慢(如触发了扩容),但多次操作的平均代价为该复杂度。
平均:输入分布理想情况下的期望复杂度。比如,对散列表指哈希均匀分布;对 BST 指随机插入。
链式实现的常数时间通常高于数组实现(指针间接访问、缓存不友好),同一复杂度的链式实际运行时间可能更长。
## 2. 使用说明
可以看 [examples](./examples/) 。
| 示例 | 主要容器 | 算法/场景 |
| --------------------------- | ------------- | ----------------- |
| `calculator.cpp` | `ArrayStack` | 中缀表达式求值 |
| `simulate_bank_queuing.cpp` | `ArrayQueue` | 多窗口排队模拟 |
| `metro_planner.cpp` | `MatrixGraph` | Dijkstra 最短路径 |
运行示例和测试:
```
xmake run example
xmake run test
```
运行 xmake run example 后进入菜单;运行 xmake run test 会执行所有测试。
其实最大的用处就是通过源码来学习/收藏/展示数据结构。
如果你想要实用的容器库/类型库,可以看看我的另一个项目:[PyInCpp](https://github.com/chen-qingyu/pyincpp)。
## 3. 开发历史
这个项目始于 2019 年,当时自学数据结构边学边写的,用的 C 语言,当做练手项目。起源详情请见: https://zhuanlan.zhihu.com/p/92786307 。因为本科专业并不是计算机,所以当时没有学软件工程,写出来的代码只是能用,但是非常不优雅。后来接触到了面向对象思想和软件工程实践,我把整个项目推翻重写了好几次。2023年完成了第一版。
最开始那几年我根本没有把这个项目开源的想法,因为我觉得这只是我的一个个人练手作品,网上一搜一大把,没什么开源价值。但是后来陆陆续续把它功能写得很完善的时候,我发现其中有些功能的实现互联网上基本搜不到,比如字符串转数字(类似标准库的 atof ,但是这个库不依赖 string.h ,没错我是重新造轮子),我能找到的都不能与标准库相媲美,各种瑕疵(不能处理类似 ".123e-2" 这种情况,或者不能识别 nan 以及 inf ),而有些又太冗杂(各种 if else 嵌套),我想了两天最后用 FPGA 里面的独热码思想结合有限状态机实现了(后来把 `String` 合并到 `PyInCpp` 里去了,因为 `String` 严格来说不算数据结构而算数据类型)。类似的还有许多,都是我在日积月累的学习中一行一行写出来的。有时候是灵光乍现(比如`String_ToDecimal, String_ToInteger`的独热码结合有限状态机),有时候是从其他语言的标准库中得到的启发(比如`String_From`的命名仿照 Rust 标准库中 String 的 from 方法),有时候是网友给的建议(比如`DoublyLinkedList_At`的内部状态指针加速访问)。
因为二叉树的中序遍历需要用到队列,而 C 语言无法简洁地实现泛型,所以之前一直是把队列函数源码复制一份当成`static`的然后 `typedef const struct BinarySearchTreeNode* ArrayQueueItem;` 手动模拟泛型,但这样太不优雅了,2024 年用 C++ 重写了,发布了v2.0.0,原先的 C 语言版本保留在 branch v1 中。
2025 年持续迭代,新增了许多数据结构,打磨了许多细节。
2026 年引入了基于 Concept + Model 的类型擦除迭代器,统一了所有容器的迭代器接口,大幅简化了代码。然后新增了一些新的数据结构,同时对项目进行了全面的 C++23 合规性加固和优化。
项目已经很优雅了,我猜认真阅读代码的人都会发出一句感叹:"优雅!"。