行业知识
【嵌入式高级C语言】9:万能型链表懒人手册
文章目录
- 序言
- 单向不循环链表
- 拼图框架搭建 - `Necessary`
- 功能拼图块
- 1 创建链表头信息结构体 - `Necessary`
- 2 链表头部插入 - `Optional`
- 3 链表的遍历 - `Optional`
- 4 链表的销毁 - `Necessary`
- 5 链表头信息结构体销毁 - `Necessary`
- 6 获取链表中节点的个数 - `Optional`
- 7 链表尾部插入 - `Optional`/`Dependent`
- 8 链表根据索引插入数据 - `Optional`
- 9 链表根据索引删除数据 - `Optional`/`Dependent`
- 10 链表根据索引修改数据 - `Optional`/`Dependent`
- 11 链表根据索引获取数据 - `Optional`/`Dependent`
- 12 根据关键字寻找匹配索引 - `Optional`/`Dependent`
- 13 链表根据关键字删除数据 - `Optional`
- 14 链表根据关键字修改数据 - `Optional`
- 15 链表根据关键字获取数据 - `Optional`
- 16 链表根据关键字删除所有匹配的节点 - `Optional`
- 17 链表根据关键字修改所有匹配的节点 - `Optional`
- 18 链表根据关键字查找所有的索引 - `Optional`
- 19 链表的翻转 - `Optional`
- 测试代码添加模块
- 1 自定义数据销毁函数 - `Necessary`
- 2 自定义数据打印函数 - `Necessary`
- 3 自定义数据比较函数 - `Necessary`
- 测试代码参考
- 双向循环链表
- 拼图框架搭建 - `Necessary`
- 功能拼图块
- 1 创建链表头信息结构体 - `Necessary`
- 2 链表头部插入 - `Optional`/`Dependent`
- 3 链表尾部插入 - `Optional`/`Dependent`
- 4 链表的遍历 - `Optional`
- 5 链表的反向遍历 - `Optional`
- 6 链表的销毁 - `Necessary`
- 7 链表头信息结构体销毁 - `Necessary`
- 8 获取链表中节点的个数 - `Optional`
- 9 链表根据索引插入数据 - `Optional`
- 10 链表根据索引删除数据 - `Optional`/`Dependent`
- 11 链表根据索引修改数据 - `Optional`/`Dependent`
- 12 链表根据索引获取数据 - `Optional`/`Dependent`
- 13 根据关键字寻找匹配索引 - `Optional`/`Dependent`
- 14 链表根据关键字删除数据 - `Optional`
- 15 链表根据关键字修改数据 - `Optional`
- 16 链表根据关键字获取数据 - `Optional`
- 17 链表根据关键字删除所有匹配的节点 - `Optional`
- 18 链表根据关键字修改所有匹配的节点 - `Optional`
- 19 链表根据关键字查找所有的索引 - `Optional`
- 测试代码添加模块
- 1 自定义数据销毁函数 - `Necessary`
- 2 自定义数据打印函数 - `Necessary`
- 3 自定义数据比较函数 - `Necessary`
- 测试代码分享
- 附录
序言
���链表篇意在制作所有人都可拿来即用的万能型链表懒人拼装手册,使用门槛低,不需要使用者有很深的语言和数据结构理解,使用简单且有参考代码。如使用本手册进行链表的学习也是一种绝佳的体验,源码注释丰富且逻辑清晰,相信读者可以在轻松愉快的环境下学习掌握。如果全部理解并掌握此手册,相信你对于绝大部分链表及数据操作已然不成问题,借此打下良好的基础便于日后面对更加复杂的挑战。
万能型链表义如其名,可以存储任何数据类型,只有你想不到的,没有它存不了的,但是需要读者注意其使用技巧(必要时请参考附录)。
在开始前,本人在这里借用戴尔·卡耐基的一句话祝各位学习路上可以披荆斩棘,乘风破浪,一往直前。
多数人都拥有自己不了解的能力和机会,都有可能做到未曾梦想的事情。
——戴尔·卡耐基
单向不循环链表
拼图框架搭建 - Necessary
.h
#ifndef ___h__#define ___h__#include #include #include // 匹配成功#define MATCH_SUCCESS 0// 匹配失败#define MATCH_FAIL -3// 调试宏#define DEBUG#define _FILE_DEBUG// 函数功能错误#define FUN_ERROR -1// 参数错误#define PAR_ERROR -2// 类型定义typedef int(*op_t)(void *data);typedef int(*cmp_t)(void *data, void *key);/** * @brief 链表节点定义 */typedef struct _node_t{ void *data; // 数据域 struct _node_t *next; // 指针域}node_t;/** * @brief 链表头信息结构体定义 */typedef struct _uolist_t{ node_t *fstnode_p; // 指向链表的第一个节点 int size; // 存储数据的类型大小 int count; // 节点的个数 op_t my_destroy; // 自定义销毁函数}uolist_t;/********************************** 请在这个区域内添加功能拼图 ***********************************//***********************************************************************************************/#endif.c
#include ".h"/** * @brief 创建节点空间 * @param 链表头信息结构体指针 * @return 节点指针 */static node_t *__node_calloc(uolist_t *uo){ /* 变量定义 */ node_t *p = NULL; /* 参数检查 */ if (NULL == uo) { #ifdef DEBUG printf("__node_calloc: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo) */ /* 创建节点空间 */ p = (node_t *)calloc(1, sizeof(node_t)); if (NULL == p) { #ifdef DEBUG printf("__node_calloc: p calloc error\n"); #elif defined FILE_DEBUG #endif goto ERR1; } /* end of if (NULL == p) */ /* 创建节点中数据空间 */ p->data = (void *)calloc(1, uo->size); if (NULL == p->data) { #ifdef DEBUG printf("__node_calloc: data calloc error\n"); #elif defined FILE_DEBUG #endif goto ERR2; } /* end of if (NULL == p->data) */ return p;ERR0: return (void *)PAR_ERROR;ERR2: free(p); p = NULL;ERR1: return (void *)FUN_ERROR;}/****************************************请在下方添加功能块拼图************************************************/功能拼图块
1 创建链表头信息结构体 - Necessary
.h功能添加区
/** * @brief 创建链表头信息结构体 * @param 存储数据类型大小 * @param 自定义销毁数据函数 * @return 指向链表头信息结构体的指针 */uolist_t *uolist_create(int size, op_t my_destroy);
.c功能添加区
/** * @brief 创建链表头信息结构体 * @param 存储数据类型大小 * @param 自定义销毁数据函数 * @return 指向链表头信息结构体的指针 */uolist_t *uolist_create(int size, op_t my_destroy){ /* 变量定义 */ uolist_t *uo = NULL; /* 参数检查 */ if (size #ifdef DEBUG printf("uolist_create: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (size #ifdef DEBUG printf("uolist_create: calloc error\n"); #elif defined FILE_DEBUG #endif goto ERR1; } /* end of if (NULL == uo) */ /* 信息输入 */ uo-count = 0; uo-size = size; uo->fstnode_p = NULL; uo->my_destroy = my_destroy; return uo;ERR0: return (void *)PAR_ERROR;ERR1: return (void *)FUN_ERROR;}2 链表头部插入 - Optional
.h功能添加区
/** * @brief 链表头部插入 * @param 头信息结构体的指针 * @param 插入节点数据 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_prepend(uolist_t *uo, void *data);
.c功能添加区
/** * @brief 链表头部插入 * @param 头信息结构体的指针 * @param 插入节点数据 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_prepend(uolist_t *uo, void *data){ node_t *temp1 = NULL; node_t *temp2 = NULL; /* 参数检查 */ if (NULL == uo || NULL == data) { #ifdef DEBUG printf("uolist_prepend: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == data) */ /* 1.创建一个新的节点 */ temp1 = __node_calloc(uo); /* 2.节点数据输入 */ temp1->next = NULL; memcpy(temp1->data, data, uo->size); /* 3.链表节点头部插入 */ if (NULL == uo->fstnode_p) { uo->fstnode_p = temp1; } else { temp2 = uo->fstnode_p; uo->fstnode_p = temp1; temp1->next = temp2; } /* 链表头信息更新 */ uo->count++; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR;}3 链表的遍历 - Optional
.h功能添加区
/** * @brief 链表的遍历 * @param 头信息结构体的指针 * @param 自定义打印数据函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_traverse(uolist_t *uo, op_t my_print);
.c功能添加区
/** * @brief 链表的遍历 * @param 头信息结构体的指针 * @param 自定义打印数据函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_traverse(uolist_t *uo, op_t my_print){ node_t *temp = NULL; /* 参数检查 */ if (NULL == uo || NULL == my_print) { #ifdef DEBUG printf("uolist_traverse: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == my_print) */ /* 链表的遍历 */ temp = uo->fstnode_p; while (temp != NULL) { my_print(temp->data); temp = temp->next; } /* end of while (temp != NULL) */ return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }4 链表的销毁 - Necessary
.h功能添加区
/** * @brief 链表销毁函数(不包括头信息结构体) * @param 头信息结构体的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_destroy(uolist_t *uo);
.c功能添加区
/** * @brief 链表销毁函数(不包括头信息结构体) * @param 头信息结构体的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_destroy(uolist_t *uo){ node_t *temp = NULL; node_t *save = NULL; /* 参数检查 */ if (NULL == uo) { #ifdef DEBUG printf("uolist_destroy: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo) */ temp = uo->fstnode_p; /* 依次释放节点空间 */ while (NULL != temp) { /* 1.保存下个节点的指针 */ save = temp->next; /* 2.释放数据空间 */ uo->my_destroy(temp->data); temp->data = NULL; /* 3.释放节点空间 */ free(temp); temp = NULL; /* 4.指向下一个节点 */ temp = save; } /* end of while (NULL != temp) */ /* 头信息刷新 */ uo->fstnode_p = NULL; uo->count = 0; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }5 链表头信息结构体销毁 - Necessary
.h功能添加区
/** * @brief 头信息结构体销毁函数 * @param 头信息结构体的指针的地址 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int head_destroy(uolist_t **p);
.c功能添加区
/** * @brief 头信息结构体销毁函数 * @param 头信息结构体的指针的地址 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int head_destroy(uolist_t **p){ /* 参数检查 */ if (NULL == p) { #ifdef DEBUG printf("head_destroy: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == p) */ /* 销毁结构体空间 */ free(*p); *p = NULL; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }6 获取链表中节点的个数 - Optional
.h功能添加区
/** * @brief 获取链表中节点的个数 * @param 头信息结构体的指针 * @return 链表节点个数 */int get_count(uolist_t *p);
.c功能添加区
/** * @brief 获取链表中节点的个数 * @param 头信息结构体的指针 * @return 链表节点个数 */int get_count(uolist_t *p){ /* 参数检查 */ if (NULL == p) { #ifdef DEBUG printf("get_count: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == p) */ return p->count;ERR0: return PAR_ERROR;}7 链表尾部插入 - Optional/Dependent
.h功能添加区
/** * @brief 链表尾部插入 * @param 头信息结构体的指针 * @param 数据的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_append(uolist_t *uo, void *data);
.c功能添加区
/** * @brief 链表尾部插入 * @param 头信息结构体的指针 * @param 数据的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_append(uolist_t *uo, void *data){ node_t *temp1 = NULL; node_t *temp2 = NULL; /* 参数检查 */ if (NULL == uo || NULL == data) { #ifdef DEBUG printf("uolist_append: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == data) */ /* 1.创建一个新的节点 */ temp1 = __node_calloc(uo); /* 2.节点数据输入 */ temp1->next = NULL; memcpy(temp1->data, data, uo->size); /* 3.数据尾部插入 */ if (NULL == uo->fstnode_p) { uo->fstnode_p = temp1; } else { temp2 = uo->fstnode_p; while (temp2->next != NULL) { temp2 = temp2->next; } /* end of while (temp2->next != NULL) */ temp2->next = temp1; } /* 4.刷新信息 */ uo->count++; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }8 链表根据索引插入数据 - Optional
.h功能添加区
/** * @brief 链表根据索引插入 * @param 头信息结构体的指针 * @param 数据的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_insert_by_index(uolist_t *uo, void *data, int index);
.c功能添加区
/** * @brief 链表根据索引插入 * @param 头信息结构体的指针 * @param 数据的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_insert_by_index(uolist_t *uo, void *data, int index){ node_t *temp1 = NULL; node_t *temp2 = NULL; node_t *save = NULL; int i = 0; /* 参数检查 */ if (NULL == uo || NULL == data || index next = NULL; memcpy(temp1->data, data, uo->size); /* 3.判断索引 */ temp2 = uo->fstnode_p; if (index count && index > 0) { // 寻找索引位置 for (i = 0; i next; } /* end of for (i = 0; i next; // 在索引位置插入新节点 temp2->next = temp1; // 链接保存链表 temp1->next = save; } else if (index == 0) { // 头部插入 uo->fstnode_p = temp1; temp1->next = temp2; } else { // 尾部插入 while (temp2->next != NULL) { temp2 = temp2->next; } /* end of while (temp2->next != NULL) */ temp2->next = temp1; } /* 刷新管理信息 */ uo->count++; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }9 链表根据索引删除数据 - Optional/Dependent
.h功能添加区
/** * @brief 链表根据索引删除 * @param 头信息结构体的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_delete_by_index(uolist_t *uo, int index);
.c功能添加区
/** * @brief 链表根据索引删除 * @param 头信息结构体的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_delete_by_index(uolist_t *uo, int index){ node_t *temp1 = NULL; node_t *temp2 = NULL; node_t *des = NULL; int i = 0; /* 参数检查 */ if (NULL == uo || index = uo->count) { #ifdef DEBUG printf("uolist_delete_by_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || index = uo->count) */ /* 寻找索引的前一个 */ if (index == 0) { // 保存节点 des = uo->fstnode_p; temp2 = uo->fstnode_p->next; // 连接节点 uo->fstnode_p = temp2; // 释放节点 uo->my_destroy(des->data); free(des); des = NULL; } else { // 寻找并保存节点 temp1 = uo->fstnode_p; for (i = 0; i next; } /* end of for (i = 0; i next->next; des = temp1->next; // 连接节点 temp1->next = temp2; // 释放节点 uo->my_destroy(des->data); free(des); des = NULL; } /* 刷新信息 */ uo->count--; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }10 链表根据索引修改数据 - Optional/Dependent
.h功能添加区
/** * @brief 链表根据索引修改数据 * @param 头信息结构体的指针 * @param 修改数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_modify_by_index(uolist_t *uo, void *data, int index);
.c功能添加区
/** * @brief 链表根据索引修改数据 * @param 头信息结构体的指针 * @param 修改数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_modify_by_index(uolist_t *uo, void *data, int index){ int i = 0; node_t *temp = NULL; /* 参数检查 */ if (NULL == uo || index = uo->count || NULL == data) { #ifdef DEBUG printf("uolist_modify_by_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || index = uo->count || NULL == data) */ /* 寻找索引位置 */ temp = uo->fstnode_p; for (i = 0; i next; } /* end of for (i = 0; i data, data, uo->size); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }11 链表根据索引获取数据 - Optional/Dependent
.h功能添加区
/** * @brief 链表根据索引检索数据 * @param 头信息结构体的指针 * @param 要检索的数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_retrieve_by_index(uolist_t *uo, void *data, int index);
.c功能添加区
/** * @brief 链表根据索引检索数据 * @param 头信息结构体的指针 * @param 要检索的数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_retrieve_by_index(uolist_t *uo, void *data, int index){ int i = 0; node_t *temp = NULL; /* 参数检查 */ if (NULL == uo || index = uo->count || NULL == data) { #ifdef DEBUG printf("uolist_retrieve_by_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || index = uo->count || NULL == data) */ /* 寻找索引位置 */ temp = uo->fstnode_p; for (i = 0; i next; } /* end of for (i = 0; i data, uo->size); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }12 根据关键字寻找匹配索引 - Optional/Dependent
.h功能添加区
/** * @brief 根据关键字寻找匹配索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 索引值 * @arg PAR_ERROR:参数错误 * @arg MATCH_FAIL:无匹配索引 */int get_match_index(uolist_t *uo, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 根据关键字寻找匹配索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 索引值 * @arg PAR_ERROR:参数错误 * @arg MATCH_FAIL:无匹配索引 */int get_match_index(uolist_t *uo, void *key, cmp_t op_cmp){ int index = 0; node_t *temp = NULL; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("get_match_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */ /* 判断是否为空链表 */ if (NULL == uo->fstnode_p) { goto ERR1; } /* end of if (NULL == uo->fstnode_p) */ /* 寻找匹配索引 */ index = 0; temp = uo->fstnode_p; while (1) { if (MATCH_SUCCESS == op_cmp(temp->data, key)) { return index; } /* end of if (MATCH_SUCCESS == op_cmp(temp->data, key)) */ temp = temp->next; if (NULL == temp) { goto ERR1; } /* end of if (NULL == temp) */ index++; } /* end of while (1) */ERR0: return PAR_ERROR;ERR1: return MATCH_FAIL; }13 链表根据关键字删除数据 - Optional
.h功能添加区
/** * @brief 链表根据关键字删除 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_delete_by_key(uolist_t *uo, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字删除 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_delete_by_key(uolist_t *uo, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("uolist_delete_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */ /* 获取匹配索引 */ index = get_match_index(uo, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引删除节点 */ uolist_delete_by_index(uo, index); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加9、12功能。
14 链表根据关键字修改数据 - Optional
.h功能添加区
/** * @brief 链表根据关键字修改数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_modify_by_key(uolist_t *uo, void *data, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字修改数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_modify_by_key(uolist_t *uo, void *data, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) { #ifdef DEBUG printf("uolist_modify_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) */ /* 获取匹配索引 */ index = get_match_index(uo, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引修改数据 */ uolist_modify_by_index(uo, data, index); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加10、12功能。
15 链表根据关键字获取数据 - Optional
.h功能添加区
/** * @brief 链表根据关键字获取数据 * @param 头信息结构体的指针 * @param 获取的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_retrieve_by_key(uolist_t *uo, void *data, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字获取数据 * @param 头信息结构体的指针 * @param 获取的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_retrieve_by_key(uolist_t *uo, void *data, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) { #ifdef DEBUG printf("uolist_retrieve_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) */ /* 获取匹配索引 */ index = get_match_index(uo, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引获取数据 */ uolist_retrieve_by_index(uo, data, index); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加11、12功能。
16 链表根据关键字删除所有匹配的节点 - Optional
.h功能添加区
/** * @brief 链表根据关键字删除所有匹配的节点 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_delete_all_by_key(uolist_t *uo, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字删除所有匹配的节点 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_delete_all_by_key(uolist_t *uo, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("uolist_delete_all_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */ while (1) { /* 获取匹配索引 */ index = get_match_index(uo, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引删除节点 */ uolist_delete_by_index(uo, index); } /* end of while (1) */ return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加9、12功能。
17 链表根据关键字修改所有匹配的节点 - Optional
.h功能添加区
/** * @brief 链表根据关键字修改所有匹配节点的数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_modify_all_by_key(uolist_t *uo, void *data, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字修改所有匹配节点的数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int uolist_modify_all_by_key(uolist_t *uo, void *data, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) { #ifdef DEBUG printf("uolist_modify_all_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) */ while (1) { /* 获取匹配索引 */ index = get_match_index(uo, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引修改数据 */ uolist_modify_by_index(uo, data, index); } /* end of while (1) */ return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加10、12功能。
18 链表根据关键字查找所有的索引 - Optional
.h功能添加区
/** * @brief 链表根据关键字查找所有的索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 存储索引链表 * @arg PAR_ERROR: 参数错误 * @arg NULL : 没有找到匹配索引 */uolist_t *uolist_find_all_index_by_key(uolist_t *uo, void *key, cmp_t op_cmp);/** * @brief 自定义索引销毁函数 * @param 数据域 * @return 0 */int index_destroy(void *data);/** * @brief 自定义索引打印函数 * @param 数据域 * @return 0 */int index_print(void *data);
.c功能添加区
/** * @brief 链表根据关键字查找所有的索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 存储索引链表 * @arg PAR_ERROR: 参数错误 * @arg NULL : 没有找到匹配索引 */uolist_t *uolist_find_all_index_by_key(uolist_t *uo, void *key, cmp_t op_cmp){ uolist_t *index_head = NULL; node_t *temp = NULL; int index = 0; /* 参数检查 */ if (NULL == uo || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("uolist_find_all_index_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */ /* 判断链表是否存在 */ if (NULL == uo->fstnode_p) { goto ERR1; } /* end of if (NULL == uo->fstnode_p) */ /* 创建存储索引的链表头信息结构体 */ index_head = uolist_create(sizeof(int), index_destroy); /* 查找索引并插入链表 */ temp = uo->fstnode_p; for (index = 0; NULL != temp; index++, temp = temp->next) { if (MATCH_SUCCESS == op_cmp(temp->data, key)) { uolist_append(index_head, &index); } } /* end of for (index = 0; NULL != temp; index++, temp = temp->next) */ /* 判断是否为空链表 */ if (0 == get_count(index_head)) { head_destroy(&index_head); } /* end of if (0 == get_count(index_head)) */ return index_head;ERR0: return (void *)PAR_ERROR;ERR1: return NULL;}/** * @brief 自定义索引销毁函数 * @param 数据域 * @return 0 */int index_destroy(void *data){ free(data); data = NULL; return 0;}/** * @brief 自定义索引打印函数 * @param 数据域 * @return 0 */int index_print(void *data){ printf("index = %d\n", *(int *)data); return 0;}使用此功能同时需要添加7功能。
19 链表的翻转 - Optional
.h功能添加区
/** * @brief 链表的翻转 * @param 头信息结构体的指针 * @return * @arg PAR_ERROR: 参数错误 * @arg 0 : 正常 */int uolist_reverse(uolist_t *uo);
.c功能添加区
/** * @brief 链表的翻转 * @param 头信息结构体的指针 * @return * @arg PAR_ERROR: 参数错误 * @arg 0 : 正常 */int uolist_reverse(uolist_t *uo){ node_t *p = NULL; node_t *save = NULL; node_t *temp = NULL; /* 参数检查 */ if (NULL == uo) { #ifdef DEBUG printf("uolist_reverse: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == uo) */ /* 链表的翻转 */ for (p = uo->fstnode_p, uo->fstnode_p = NULL, uo->count = 0; NULL != p; p = save) { /* 保存下一个节点 */ save = p->next; /* 链表头插 */ p->next = NULL; if (NULL == uo->fstnode_p) { uo->fstnode_p = p; } else { temp = uo->fstnode_p; uo->fstnode_p = p; p->next = temp; } /* 链表头信息更新 */ uo->count++; } /* end of for (p = uo->fstnode_p, uo->fstnode_p = NULL, uo->count = 0; NULL != p; p = save) */ return 0;ERR0: return PAR_ERROR;}测试代码添加模块
1 自定义数据销毁函数 - Necessary
int node_destroy(void *data){}2 自定义数据打印函数 - Necessary
int data_print(void *data){}3 自定义数据比较函数 - Necessary
int data_compare(void *data, void *key){}测试代码参考
test.c
/* 普通存储(int)变量测试代码 */#include #include ".h"/* 自定义节点中数据域销毁函数 */int node_destroy(void *data){ free(data); data = NULL; return 0;}/* 自定义数据域打印函数 */int data_print(void *data){ printf("%d\n", *(int *)data); return 0;}/* 自定义关键字比较函数 */int data_compare(void *data, void *key){ if (0 == memcmp(data, key, sizeof(int))) { return MATCH_SUCCESS; } else { return MATCH_FAIL; }}int main(int argc, char **argv){ uolist_t *index = NULL; uolist_t *head = NULL; int i = 0; int j = 0; int temp = 0; int key = 0; // 头信息结构体的创建 head = uolist_create(sizeof(int), node_destroy); // 节点插入 for (i = 1; i uolist_append(head, &i); } // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表按照索引插入 temp = 1989; uolist_insert_by_index(head, &temp, 6); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据索引修改 temp = 2024; uolist_modify_by_index(head, &temp, 6); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据索引删除 uolist_delete_by_index(head, 6); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据索引获取 uolist_retrieve_by_index(head, &temp, 6); printf("temp = %d\n", temp); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据关键字删除 key = 3; uolist_delete_by_key(head, &key, data_compare); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据关键字修改 temp = 666; key = 6; uolist_modify_by_key(head, &temp, &key, data_compare); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据关键字获取数据 temp = 0; key = 666; uolist_retrieve_by_key(head, &temp, &key, data_compare); printf("temp = %d\n", temp); // 尾差3个5 temp = 5; uolist_append(head, &temp); uolist_append(head, &temp); uolist_append(head, &temp); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据关键字查找所有的索引 key = 5; index = uolist_find_all_index_by_key(head, &key, data_compare); // 索引链表的遍历 printf("count = %d\n", get_count(index)); uolist_traverse(index, index_print); printf("==================================================\n"); // 链表根据关键字修改所有的节点 temp = 555; key = 5; uolist_modify_all_by_key(head, &temp, &key, data_compare); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表根据关键字删除所有的节点 key = 555; uolist_delete_all_by_key(head, &key, data_compare); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表的翻转 uolist_reverse(head); // 链表的遍历 printf("count = %d\n", get_count(head)); uolist_traverse(head, data_print); printf("==================================================\n"); // 链表的释放 uolist_destroy(head); uolist_destroy(index); head_destroy(&head); head_destroy(&index); return 0;}h2双向循环链表/h2 pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250422/-250422235115118.png" //p h3拼图框架搭建 - Necessary/h3 p.h#ifndef ___h__#define ___h__#include #include #include // 匹配成功#define MATCH_SUCCESS 0// 匹配失败#define MATCH_FAIL -3// 调试宏#define DEBUG#define _FILE_DEBUG// 函数功能错误#define FUN_ERROR -1// 参数错误#define PAR_ERROR -2// 类型定义typedef int(*op_t)(void *data);typedef int(*cmp_t)(void *data, void *key);/** * @brief 链表节点定义 */typedef struct _node_t{ void *data; // 数据域 struct _node_t *prev; // 前驱指针 struct _node_t *next; // 后继指针}node_t;/** * @brief 链表头信息结构体定义 */typedef struct _udlist_t{ node_t *fstnode_p; // 指向链表的第一个节点 int size; // 存储数据的类型大小 int count; // 节点的个数 op_t my_destroy; // 自定义销毁函数}udlist_t;/********************************** 请在这个区域内添加功能拼图 ***********************************//***********************************************************************************************/#endif.c
#include ".h"/** * @brief 创建节点空间 * @param 链表头信息结构体指针 * @return 节点指针 */static node_t *__node_calloc(udlist_t *ud){ /* 变量定义 */ node_t *p = NULL; /* 参数检查 */ if (NULL == ud) { #ifdef DEBUG printf("__node_calloc: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud) */ /* 创建节点空间 */ p = (node_t *)calloc(1, sizeof(node_t)); if (NULL == p) { #ifdef DEBUG printf("__node_calloc: p calloc error\n"); #elif defined FILE_DEBUG #endif goto ERR1; } /* end of if (NULL == p) */ /* 创建节点中数据空间 */ p->data = (void *)calloc(1, ud->size); if (NULL == p->data) { #ifdef DEBUG printf("__node_calloc: data calloc error\n"); #elif defined FILE_DEBUG #endif goto ERR2; } /* end of if (NULL == p->data) */ return p;ERR0: return (void *)PAR_ERROR;ERR2: free(p); p = NULL;ERR1: return (void *)FUN_ERROR;}/****************************************请在下方添加功能块拼图************************************************/功能拼图块
1 创建链表头信息结构体 - Necessary
.h功能添加区
/** * @brief 创建链表头信息结构体 * @param 存储数据类型大小 * @param 自定义销毁数据函数 * @return 指向链表头信息结构体的指针 */udlist_t *udlist_create(int size, op_t my_destroy);
.c功能添加区
/** * @brief 创建链表头信息结构体 * @param 存储数据类型大小 * @param 自定义销毁数据函数 * @return 指向链表头信息结构体的指针 */udlist_t *udlist_create(int size, op_t my_destroy){ /* 变量定义 */ udlist_t *ud = NULL; /* 参数检查 */ if (size #ifdef DEBUG printf("udlist_create: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (size #ifdef DEBUG printf("udlist_create: calloc error\n"); #elif defined FILE_DEBUG #endif goto ERR1; } /* end of if (NULL == ud) */ /* 信息输入 */ ud-count = 0; ud-size = size; ud->fstnode_p = NULL; ud->my_destroy = my_destroy; return ud;ERR0: return (void *)PAR_ERROR;ERR1: return (void *)FUN_ERROR;}2 链表头部插入 - Optional/Dependent
.h功能添加区
/** * @brief 链表头部插入 * @param 头信息结构体的指针 * @param 插入节点数据 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_prepend(udlist_t *ud, void *data);
.c功能添加区
/** * @brief 链表头部插入 * @param 头信息结构体的指针 * @param 插入节点数据 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_prepend(udlist_t *ud, void *data){ udlist_append(ud, data); ud->fstnode_p = ud->fstnode_p->prev; return 0;}使用此功能需要添加3功能。
3 链表尾部插入 - Optional/Dependent
.h功能添加区
/** * @brief 链表尾部插入 * @param 头信息结构体的指针 * @param 数据的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_append(udlist_t *ud, void *data);
.c功能添加区
/** * @brief 链表尾部插入 * @param 头信息结构体的指针 * @param 数据的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_append(udlist_t *ud, void *data){ node_t *temp1 = NULL; node_t *temp2 = NULL; /* 参数检查 */ if (NULL == ud || NULL == data) { #ifdef DEBUG printf("udlist_append: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == data) */ /* 1.创建一个新的节点 */ temp1 = __node_calloc(ud); /* 2.节点数据输入 */ temp1->next = temp1; temp1->prev = temp1; memcpy(temp1->data, data, ud->size); /* 3.数据尾部插入 */ if (0 == ud->count) { ud->fstnode_p = temp1; } else { temp2 = ud->fstnode_p->prev; ud->fstnode_p->prev = temp1; temp2->next = temp1; temp1->prev = temp2; temp1->next = ud->fstnode_p; } /* 4.刷新信息 */ ud->count++; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }4 链表的遍历 - Optional
.h功能添加区
/** * @brief 链表的遍历 * @param 头信息结构体的指针 * @param 自定义打印数据函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_traverse(udlist_t *ud, op_t my_print);
.c功能添加区
/** * @brief 链表的遍历 * @param 头信息结构体的指针 * @param 自定义打印数据函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_traverse(udlist_t *ud, op_t my_print){ node_t *temp = NULL; /* 参数检查 */ if (NULL == ud || NULL == my_print) { #ifdef DEBUG printf("udlist_traverse: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == my_print) */ /* 链表的遍历 */ temp = ud->fstnode_p; do { my_print(temp->data); temp = temp->next; } while (temp != ud->fstnode_p); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }5 链表的反向遍历 - Optional
.h功能添加区
/** * @brief 链表的反向遍历 * @param 头信息结构体的指针 * @param 自定义打印数据函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_traverse_back(udlist_t *ud, op_t my_print);
.c功能添加区
/** * @brief 链表的反向遍历 * @param 头信息结构体的指针 * @param 自定义打印数据函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_traverse_back(udlist_t *ud, op_t my_print){ node_t *temp = NULL; /* 参数检查 */ if (NULL == ud || NULL == my_print) { #ifdef DEBUG printf("udlist_traverse_back: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == my_print) */ /* 链表的遍历 */ temp = ud->fstnode_p; do { my_print(temp->data); temp = temp->prev; } while (temp != ud->fstnode_p); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }6 链表的销毁 - Necessary
.h功能添加区
/** * @brief 链表销毁函数(不包括头信息结构体) * @param 头信息结构体的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_destroy(udlist_t *ud);
.c功能添加区
/** * @brief 链表销毁函数(不包括头信息结构体) * @param 头信息结构体的指针 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_destroy(udlist_t *ud){ node_t *temp = NULL; node_t *save = NULL; /* 参数检查 */ if (NULL == ud) { #ifdef DEBUG printf("udlist_destroy: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud) */ temp = ud->fstnode_p; /* 依次释放节点空间 */ if (NULL != temp) { do { /* 1.保存下个节点的指针 */ save = temp->next; /* 2.释放数据空间 */ ud->my_destroy(temp->data); temp->data = NULL; /* 3.释放节点空间 */ free(temp); temp = NULL; /* 4.指向下一个节点 */ temp = save; } while (temp != ud->fstnode_p); } /* end of if (NULL != temp) */ /* 头信息刷新 */ ud->fstnode_p = NULL; ud->count = 0; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }7 链表头信息结构体销毁 - Necessary
.h功能添加区
/** * @brief 头信息结构体销毁函数 * @param 头信息结构体的指针的地址 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int head_destroy(udlist_t **p);
.c功能添加区
/** * @brief 头信息结构体销毁函数 * @param 头信息结构体的指针的地址 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int head_destroy(udlist_t **p){ /* 参数检查 */ if (NULL == p) { #ifdef DEBUG printf("head_destroy: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == p) */ /* 销毁结构体空间 */ free(*p); *p = NULL; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }8 获取链表中节点的个数 - Optional
.h功能添加区
/** * @brief 获取链表中节点的个数 * @param 头信息结构体的指针 * @return 链表节点个数 */int get_count(udlist_t *p);
.c功能添加区
/** * @brief 获取链表中节点的个数 * @param 头信息结构体的指针 * @return 链表节点个数 */int get_count(udlist_t *p){ /* 参数检查 */ if (NULL == p) { #ifdef DEBUG printf("get_count: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == p) */ return p->count;ERR0: return PAR_ERROR; }9 链表根据索引插入数据 - Optional
.h功能添加区
/** * @brief 链表根据索引插入 * @param 头信息结构体的指针 * @param 数据的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_insert_by_index(udlist_t *ud, void *data, int index);
.c功能添加区
/** * @brief 链表根据索引插入 * @param 头信息结构体的指针 * @param 数据的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_insert_by_index(udlist_t *ud, void *data, int index){ node_t *temp1 = NULL; node_t *temp2 = NULL; node_t *save = NULL; int i = 0; /* 参数检查 */ if (NULL == ud || NULL == data || index fstnode_p; if (index count && index > 0) { // 创建一个新的节点 temp1 = __node_calloc(ud); // 节点数据输入 temp1->next = temp1; temp1->prev = temp1; memcpy(temp1->data, data, ud->size); // 寻找索引位置 for (i = 0; i next; } /* end of for (i = 0; i next; // 链接新节点 save->prev = temp1; temp2->next = temp1; temp1->prev = temp2; temp1->next = save; // 刷新管理信息 ud->count++; } else if (index == 0) { // 头部插入 udlist_prepend(ud, data); } else { // 尾部插入 udlist_append(ud, data); } return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能需要添加3、2功能。
10 链表根据索引删除数据 - Optional/Dependent
.h功能添加区
/** * @brief 链表根据索引删除 * @param 头信息结构体的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_delete_by_index(udlist_t *ud, int index);
.c功能添加区
/** * @brief 链表根据索引删除 * @param 头信息结构体的指针 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_delete_by_index(udlist_t *ud, int index){ node_t *temp1 = NULL; node_t *temp2 = NULL; node_t *des = NULL; int i = 0; /* 参数检查 */ if (NULL == ud || index = ud->count) { #ifdef DEBUG printf("udlist_delete_by_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || index = ud->count) */ /* 寻找索引的前一个 */ if (index == 0) { // 保存节点 des = ud->fstnode_p; temp1 = ud->fstnode_p->prev; temp2 = ud->fstnode_p->next; // 连接节点 temp1->next = temp2; temp2->prev = temp1; ud->fstnode_p = temp2; // 释放节点 ud->my_destroy(des->data); free(des); des = NULL; } else { // 寻找并保存节点 temp1 = ud->fstnode_p; for (i = 0; i next; } /* end of for (i = 0; i next->next; des = temp1->next; // 连接节点 temp1->next = temp2; temp2->prev = temp1; // 释放节点 ud->my_destroy(des->data); free(des); des = NULL; } /* 刷新信息 */ ud->count--; return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }11 链表根据索引修改数据 - Optional/Dependent
.h功能添加区
/** * @brief 链表根据索引修改数据 * @param 头信息结构体的指针 * @param 修改数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_modify_by_index(udlist_t *ud, void *data, int index);
.c功能添加区
/** * @brief 链表根据索引修改数据 * @param 头信息结构体的指针 * @param 修改数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_modify_by_index(udlist_t *ud, void *data, int index){ int i = 0; node_t *temp = NULL; /* 参数检查 */ if (NULL == ud || index = ud->count || NULL == data) { #ifdef DEBUG printf("udlist_modify_by_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || index = ud->count || NULL == data) */ /* 寻找索引位置 */ temp = ud->fstnode_p; for (i = 0; i next; } /* end of for (i = 0; i data, data, ud->size); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }12 链表根据索引获取数据 - Optional/Dependent
.h功能添加区
/** * @brief 链表根据索引检索数据 * @param 头信息结构体的指针 * @param 要检索的数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_retrieve_by_index(udlist_t *ud, void *data, int index);
.c功能添加区
/** * @brief 链表根据索引检索数据 * @param 头信息结构体的指针 * @param 要检索的数据 * @param 索引值 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_retrieve_by_index(udlist_t *ud, void *data, int index){ int i = 0; node_t *temp = NULL; /* 参数检查 */ if (NULL == ud || index = ud->count || NULL == data) { #ifdef DEBUG printf("udlist_retrieve_by_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || index = ud->count || NULL == data) */ /* 寻找索引位置 */ temp = ud->fstnode_p; for (i = 0; i next; } /* end of for (i = 0; i data, ud->size); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }13 根据关键字寻找匹配索引 - Optional/Dependent
.h功能添加区
/** * @brief 根据关键字寻找匹配索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 索引值 * @arg PAR_ERROR:参数错误 * @arg MATCH_FAIL:无匹配索引 */int get_match_index(udlist_t *ud, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 根据关键字寻找匹配索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 索引值 * @arg PAR_ERROR:参数错误 * @arg MATCH_FAIL:无匹配索引 */int get_match_index(udlist_t *ud, void *key, cmp_t op_cmp){ int index = 0; node_t *temp = NULL; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("get_match_index: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */ /* 判断是否为空链表 */ if (NULL == ud->fstnode_p) { goto ERR1; } /* end of if (NULL == ud->fstnode_p) */ /* 寻找匹配索引 */ index = 0; temp = ud->fstnode_p; while (1) { if (MATCH_SUCCESS == op_cmp(temp->data, key)) { return index; } /* end of if (MATCH_SUCCESS == op_cmp(temp->data, key)) */ temp = temp->next; if (ud->fstnode_p == temp) { goto ERR1; } /* end of if (ud->fstnode_p == temp) */ index++; } /* end of while (1) */ERR0: return PAR_ERROR;ERR1: return MATCH_FAIL; }14 链表根据关键字删除数据 - Optional
.h功能添加区
/** * @brief 链表根据关键字删除 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_delete_by_key(udlist_t *ud, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字删除 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_delete_by_key(udlist_t *ud, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("udlist_delete_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */ /* 获取匹配索引 */ index = get_match_index(ud, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引删除节点 */ udlist_delete_by_index(ud, index); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加10、13功能。
15 链表根据关键字修改数据 - Optional
.h功能添加区
/** * @brief 链表根据关键字修改数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_modify_by_key(udlist_t *ud, void *data, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字修改数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_modify_by_key(udlist_t *ud, void *data, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) { #ifdef DEBUG printf("udlist_modify_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) */ /* 获取匹配索引 */ index = get_match_index(ud, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引修改数据 */ udlist_modify_by_index(ud, data, index); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加11、13功能。
16 链表根据关键字获取数据 - Optional
.h功能添加区
/** * @brief 链表根据关键字获取数据 * @param 头信息结构体的指针 * @param 获取的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_retrieve_by_key(udlist_t *ud, void *data, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字获取数据 * @param 头信息结构体的指针 * @param 获取的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_retrieve_by_key(udlist_t *ud, void *data, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) { #ifdef DEBUG printf("udlist_retrieve_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) */ /* 获取匹配索引 */ index = get_match_index(ud, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引获取数据 */ udlist_retrieve_by_index(ud, data, index); return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加12、13功能。
17 链表根据关键字删除所有匹配的节点 - Optional
.h功能添加区
/** * @brief 链表根据关键字删除所有匹配的节点 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_delete_all_by_key(udlist_t *ud, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字删除所有匹配的节点 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_delete_all_by_key(udlist_t *ud, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("udlist_delete_all_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */ while (1) { /* 获取匹配索引 */ index = get_match_index(ud, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引删除节点 */ udlist_delete_by_index(ud, index); } /* end of while (1) */ return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加10、13功能。
18 链表根据关键字修改所有匹配的节点 - Optional
.h功能添加区
/** * @brief 链表根据关键字修改所有匹配节点的数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_modify_all_by_key(udlist_t *ud, void *data, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 链表根据关键字修改所有匹配节点的数据 * @param 头信息结构体的指针 * @param 修改的数据 * @param 关键字 * @param 自定义比较函数 * @return * @arg 0:正常 * @arg PAR_ERROR:参数错误 * @arg FUN_ERROR:函数错误 */int udlist_modify_all_by_key(udlist_t *ud, void *data, void *key, cmp_t op_cmp){ int index = 0; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) { #ifdef DEBUG printf("udlist_modify_all_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) */ while (1) { /* 获取匹配索引 */ index = get_match_index(ud, key, op_cmp); if (PAR_ERROR == index || MATCH_FAIL == index) { goto ERR1; } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */ /* 根据索引修改数据 */ udlist_modify_by_index(ud, data, index); } /* end of while (1) */ return 0;ERR0: return PAR_ERROR;ERR1: return FUN_ERROR; }使用此功能同时需要添加11、13功能。
19 链表根据关键字查找所有的索引 - Optional
.h功能添加区
/** * @brief 自定义索引销毁函数 * @param 数据域 * @return 0 */int index_destroy(void *data);/** * @brief 自定义索引打印函数 * @param 数据域 * @return 0 */int index_print(void *data);/** * @brief 链表根据关键字查找所有的索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 存储索引链表 * @arg PAR_ERROR: 参数错误 * @arg NULL : 没有找到匹配索引 */udlist_t *udlist_find_all_index_by_key(udlist_t *ud, void *key, cmp_t op_cmp);
.c功能添加区
/** * @brief 自定义索引销毁函数 * @param 数据域 * @return 0 */int index_destroy(void *data){ free(data); data = NULL; return 0;}/** * @brief 自定义索引打印函数 * @param 数据域 * @return 0 */int index_print(void *data){ printf("index = %d\n", *(int *)data); return 0;}/** * @brief 链表根据关键字查找所有的索引 * @param 头信息结构体的指针 * @param 关键字 * @param 自定义比较函数 * @return 存储索引链表 * @arg PAR_ERROR: 参数错误 * @arg NULL : 没有找到匹配索引 */udlist_t *udlist_find_all_index_by_key(udlist_t *ud, void *key, cmp_t op_cmp){ udlist_t *index_head = NULL; node_t *temp = NULL; int index = 0; /* 参数检查 */ if (NULL == ud || NULL == key || NULL == op_cmp) { #ifdef DEBUG printf("udlist_find_all_index_by_key: Parameter error\n"); #elif defined FILE_DEBUG #endif goto ERR0; } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */ /* 判断链表是否存在 */ if (NULL == ud->fstnode_p) { goto ERR1; } /* end of if (NULL == ud->fstnode_p) */ /* 创建存储索引的链表头信息结构体 */ index_head = udlist_create(sizeof(int), index_destroy); /* 查找索引并插入链表 */ temp = ud->fstnode_p; index = 0; do { if (MATCH_SUCCESS == op_cmp(temp->data, key)) { udlist_append(index_head, &index); } /* end of if (MATCH_SUCCESS == op_cmp(temp->data, key)) */ index++; temp = temp->next; } while (temp != ud->fstnode_p); /* 判断是否为空链表 */ if (0 == get_count(index_head)) { head_destroy(&index_head); } /* end of if (0 == get_count(index_head)) */ return index_head;ERR0: return (void *)PAR_ERROR;ERR1: return NULL;}使用此功能同时需要添加3功能。
测试代码添加模块
1 自定义数据销毁函数 - Necessary
int node_destroy(void *data){}2 自定义数据打印函数 - Necessary
int data_print(void *data){}3 自定义数据比较函数 - Necessary
int data_compare(void *data, void *key){}测试代码分享
test.c
#include "uni_doubly_linkedlist.h"#include #include #include int node_destroy(void *data){ free(data); return 0;}int data_print(void *data){ printf("%d\n", *(int *)data); return 0;}int data_compare(void *data, void *key){ if (0 == memcmp(data, key, sizeof(int))) { return MATCH_SUCCESS; } else { return MATCH_FAIL; }}int main(int argc, char **argv){ udlist_t *head = NULL; udlist_t *arr_index = NULL; int temp = 0; // 创建头信息结构体 head = udlist_create(sizeof(int), node_destroy); // 插入数据 for (temp = 1; temp // udlist_append(head, &temp); udlist_prepend(head, &temp); } /* end of for (temp = 1; temp 整体换成任意名称。Necessary 该标签标注的区域是必须阅读或者执行的,否则会导致功能异常。 Optional 该标签标注的区域的阅读或者执行是可选的,忽略不会导致功能异常。 Dependent 该标签标注的区域的阅读或者执行是可选的,但是它被某些功能所依赖时则必须添加。
上一篇:怎么在服务器里面获得神兽?
下一篇:国密SM2前端加密解密示例