# unicstl ## 编译环境 - 编译器:gcc 13.2.0 - 标准:--std=c99 ## 特点 | 原理 | 优势 | 弊端 | | --- | --- |--- | | 链表 | 插入删除效率高 | 有额外指针开销 | | 动态数组 | 随机访问效率高 | 扩容时数据搬移代价较大 | | --- | --- | --- | | 单链表 | 适用内存受限场景 | 逆向不便 | | 双向链表 | 频繁双向遍历的场景(如光标移动) | 空间开销大 | ## 性能比较 | 数据结构 | < | 时 |间 | | 复 | 杂 |度 | > | <空间复杂度> | |---|---|---|---|---|---|---|---|---|---| |---|(|**平**|**均**|) | (|**最**|**坏**| ) |**最坏**| |---|访问|搜索|插入|删除|访问|搜索|插入|删除|---| | 数组 | $O(1)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | | 栈 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | | 队列 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | | 单向链表 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | | 双向链表 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | | 跳表 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n*log(n))$ | | 哈希表 | $N/A$ | $O(1)$ | $O(1)$ | $O(1)$ | $N/A$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | 二叉搜索树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | | AVL树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | | 红黑树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | | B树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | **【答疑】** 若链表的操作流程为,先查找元素再删除元素。那么时间复杂度确实是$O(n)$。但是链表的增删优势,在其他应用有体现。比如双向队列,插入和删除效率都为$O(1)$。 ## 规范 ### 版本说明 | 命名 |版本说明 | 范围 | 更新说明 | |:----: |:----:|:----:|:----:| | `VERSION_MAJOR` | 主版本号 | 0 ~ 99 | 代码框架大改,完全不兼容旧版 | | `VERSION_MINOR` | 次版本号 | 0 ~ 99 | 代码框架尽量兼容旧版,增信大功能、修复重大bug等 | | `VERSION_MICRO` | 小版本号 | 0 ~ 99 | 代码框架兼容旧版,新增小功能、修复bug等 | 举例说明: ```c // 若 major > 0 ,则代表正式发布版本 #define UNICSTL_VERSION_MAJOR 1 #define UNICSTL_VERSION_MINOR 2 #define UNICSTL_VERSION_MICRO 5 #define UNICSTL_VERSION ((UNICSTL_VERSION_MAJOR << 16) | (UNICSTL_VERSION_MINOR << 8) | UNICSTL_VERSION_MICRO) ``` ### 工程命名 `工程名(_功能)_v版本号_日期(_时间)(-其他信息)` > 括号内表示可选项 | 其他信息后缀 | 说明 | 详细 |:----:|:----:|---- | aX | alpha内测版 | 可能仅测试了新增功能,但没有测试新增功能对其他模块的影响 | bX | beta公测版 | 不仅测试了新增功能,也测试了其他模块,尽量保证新增的功能不影响原来的旧功能。 | ... | | 或者添加其他有有效信息 举例说明: ```shell unicstl_stack_v1.2.5_20240717-a0.zip # 带a或者b后缀,表示当前版本发布前的测试版。如果发布后,则直接更新版本号了 ``` ## deque实现对比 > segarray类比c++的deque,ringbuf类比rust的VecDeque ### 若capacity足够,不需要扩容 |场景 | ringbuf | segarray| 说明 |---- | --- | --- | ---- | size < capacity/2 | 无扩容 | 无扩容 | 性能一样 | size > capacity/2 | 无扩容 | 内部预留耗尽,触发段/map分配 | ringBuf连续内存缓存更优,segarray因中段起始预留,不库容容量折半 ### 若capacity不够,需要扩容 1. capacity 合理的情况下(初值预估可能大小) |场景 | ringbuf | segarray| 说明 |---- | --- | --- | ---- | objsize 很大 | 按倍数扩整体连续大内存 + 全量数据搬移 | 新分配小段、无旧数据拷贝,顶多map指针数组扩容 | segarray 碾压,规避巨型对象整体拷贝开销 | objsize 很小 | 倍数扩容开销极低,连续内存缓存友好 | 逐段分配、map偶尔扩容,间接寻址拖累缓存 | ringBuf占优;小对象拷贝成本可忽略,连续内存优势拉满 备注:C++标准库 deque 靠固定 512 字节自适应每段元素数。也即可以让segarray 借助 objsize 和 512 对比,来实现方案优化 2. capacity 非常小情况 |场景 | ringbuf | segarray| 说明 |---- | --- | --- | ---- | objsize 很大 | 每次翻倍扩连续巨块内存 + 大批量搬移大对象 | 每次只按需分配单个,少量段,永远不拷贝旧数据 | segarray 依然优势明显 | objsize 很小 | 指数倍数扩容,扩容次数少、成本低 | 退化成「类链表模式」:每插易新建段 + 频繁小分配,虽支持随机访问,但内存碎片化、分配次数暴增 | ringBuf 完胜,翻倍扩容策略吊打退化的 SegArray