# Linkedlist_shdl **Repository Path**: lee8871/linkedlist_shdl ## Basic Information - **Project Name**: Linkedlist_shdl - **Description**: S(单向)H(头指针)D(偏移量决定节点指针)L(链表)。 这个库很小,单独搞成一个仓库的这个人绝对是松耦合狂人(那就是我)。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-27 - **Last Updated**: 2025-06-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SHDL - 单向头指针偏移量引导链表库 SHDL(Single-way Head-pointer Diff-guided Linked List)是一个轻量级的C语言链表库,提供了基于偏移量的通用链表操作。 ## 特性 - **通用性**: 支持任意结构体类型作为链表节点 - **偏移量引导**: 通过指定next指针在结构体中的偏移量来操作链表 - **MCU友好**: 提供自定义的 `SHDL_OFFSETOF` 宏,避免标准库兼容性问题 - **高效操作**: 提供常用的链表操作,包括插入、删除、遍历等 - **回调支持**: 支持自定义回调函数进行条件遍历和删除 - **C语言兼容**: 纯C实现,兼容C++ ## 核心概念 ### 偏移量引导 (Diff-guided) SHDL使用偏移量来定位节点中的next指针,这使得库可以处理任意结构的节点,只要指定next指针在结构体中的偏移量即可。 ```c // 示例结构体 typedef struct Node { int data; struct Node* next; // next指针的偏移量为 SHDL_OFFSETOF(struct Node, next) } Node; ``` ### 通用指针 (tPtr) 使用 `void*` 类型的 `tPtr` 作为通用指针,可以指向任意类型的节点。 ### 自定义偏移量宏 (SHDL_OFFSETOF) 库提供了自定义的 `SHDL_OFFSETOF` 宏来计算结构体成员的偏移量,专门为MCU编译器优化: ```c #define SHDL_OFFSETOF(type, member) ((char*)&((type*)0)->member - (char*)0) ``` **优势:** - **MCU兼容**: 不依赖标准库的 `offsetof`,避免某些MCU编译器的兼容性问题 - **简单实现**: 使用纯指针算术,适用于各种编译器 - **条件编译**: 允许用户自定义实现,如果需要的话 **使用示例:** ```c typedef struct Node { int data; struct Node* next; } Node; char next_offset = SHDL_OFFSETOF(Node, next); ``` ## API 参考 ### 基本操作 #### `void Linklist_append(tPtr* head, char next_diff, tPtr new_node)` 在链表末尾添加新节点。 **参数:** - `head`: 链表头指针的地址 - `next_diff`: next指针在节点结构中的偏移量 - `new_node`: 要添加的新节点 #### `void Linklist_prepend(tPtr* head, char next_diff, tPtr new_node)` 在链表头部插入新节点。 **参数:** - `head`: 链表头指针的地址 - `next_diff`: next指针在节点结构中的偏移量 - `new_node`: 要插入的新节点 #### `tPtr Linklist_removeFirst(tPtr* head, char next_diff)` 删除并返回链表的第一个节点。 **参数:** - `head`: 链表头指针的地址 - `next_diff`: next指针在节点结构中的偏移量 **返回值:** 被删除的节点指针,如果链表为空则返回 `nullptr` #### `tPtr Linklist_removeLast(tPtr* head, char next_diff)` 删除并返回链表的最后一个节点。 **参数:** - `head`: 链表头指针的地址 - `next_diff`: next指针在节点结构中的偏移量 **返回值:** 被删除的节点指针,如果链表为空则返回 `nullptr` ### 高级操作 #### `int Linklist_foreach(tPtr* head, char next_diff, int (*callback)(tPtr node, void* tag), void* tag)` 遍历链表并对每个节点执行回调函数。 **参数:** - `head`: 链表头指针的地址 - `next_diff`: next指针在节点结构中的偏移量 - `callback`: 对每个节点执行的回调函数 - `tag`: 传递给回调函数的用户自定义数据 **返回值:** 被回调函数终止遍历的节点序号(从0开始),或链表长度(如果遍历完成) **回调函数返回值控制:** - `0` (eIterateCtrl_Continue): 继续遍历 - `1` (eIterateCtrl_Stop): 停止遍历 #### `int Linklist_removeIf(tPtr* head, char next_diff, int (*predicate)(tPtr node, void* tag), void* tag)` 遍历链表并删除所有符合条件的节点。 **参数:** - `head`: 链表头指针的地址 - `next_diff`: next指针在节点结构中的偏移量 - `predicate`: 判断函数,对每个节点进行检查 - `tag`: 传递给判断函数的用户自定义数据 **返回值:** 删除的节点数量 **判断函数返回值控制:** - `0` (eIterateCtrl_Continue): 继续遍历,不删除当前节点 - `1` (eIterateCtrl_Stop): 停止遍历,不删除当前节点 - `2` (eIterateCtrl_Remove): 删除当前节点并继续遍历 - `3` (eIterateCtrl_RemoveStop): 删除当前节点并停止遍历 ## 使用示例 ### 基本使用 ```c #include "shdl.h" #include #include // 定义节点结构 typedef struct IntNode { int value; struct IntNode* next; } IntNode; int main() { // 初始化链表 tPtr head = NULL; char next_offset = SHDL_OFFSETOF(IntNode, next); // 创建节点 IntNode* node1 = malloc(sizeof(IntNode)); node1->value = 10; node1->next = NULL; IntNode* node2 = malloc(sizeof(IntNode)); node2->value = 20; node2->next = NULL; IntNode* node3 = malloc(sizeof(IntNode)); node3->value = 30; node3->next = NULL; // 添加节点到链表 Linklist_append(&head, next_offset, node1); Linklist_append(&head, next_offset, node2); Linklist_prepend(&head, next_offset, node3); // 链表现在的顺序是: 30 -> 10 -> 20 // 删除第一个节点 IntNode* removed = (IntNode*)Linklist_removeFirst(&head, next_offset); printf("删除的节点值: %d\n", removed->value); // 输出: 30 free(removed); return 0; } ``` ### 使用回调函数遍历 ```c // 打印节点值的回调函数 int print_node(tPtr node, void* tag) { IntNode* int_node = (IntNode*)node; printf("节点值: %d\n", int_node->value); return 0; // 继续遍历 } // 使用foreach遍历链表 int count = Linklist_foreach(&head, next_offset, print_node, NULL); printf("链表总长度: %d\n", count); ``` ### 条件删除节点 ```c // 删除所有偶数值节点的判断函数 int remove_even(tPtr node, void* tag) { IntNode* int_node = (IntNode*)node; if (int_node->value % 2 == 0) { return 2; // 删除当前节点并继续 } return 0; // 不删除,继续遍历 } // 删除所有偶数值的节点 int removed_count = Linklist_removeIf(&head, next_offset, remove_even, NULL); printf("删除了 %d 个偶数节点\n", removed_count); ``` ## 编译和使用 ### 编译 ```bash gcc -c shdl.c -o shdl.o gcc your_program.c shdl.o -o your_program ``` ### 头文件包含 ```c #include "shdl.h" ``` ## 注意事项 1. **内存管理**: 库不负责节点的内存分配和释放,用户需要自行管理 2. **偏移量计算**: 建议使用库提供的 `SHDL_OFFSETOF` 宏来计算偏移量,适用于各种MCU编译器 3. **空指针检查**: 在使用返回的节点指针前,请检查是否为 `nullptr` 4. **回调函数**: 回调函数中不应修改链表结构 5. **线程安全**: 库不是线程安全的,多线程环境下需要额外的同步机制 ## 许可证 本项目由 lee8871@126.com 开发,请根据项目需要选择合适的许可证。 ## 贡献 欢迎提交问题报告和改进建议。 ---