【嵌入式高级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
< name >.h
#ifndef __< name >_h__
#define __< name >_h__#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 匹配成功
#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
< name >.c
#include "< name >.h"/*** @brief 创建节点空间* @param 链表头信息结构体指针* @return 节点指针*/
static node_t *__node_calloc(uolist_t *uo)
{/* 变量定义 */node_t *p = NULL;/* 参数检查 */if (NULL == uo){#ifdef DEBUGprintf("__node_calloc: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == uo) *//* 创建节点空间 */ p = (node_t *)calloc(1, sizeof(node_t));if (NULL == p){#ifdef DEBUGprintf("__node_calloc: p calloc error\n");#elif defined FILE_DEBUG#endifgoto ERR1; } /* end of if (NULL == p) *//* 创建节点中数据空间 */p->data = (void *)calloc(1, uo->size);if (NULL == p->data){#ifdef DEBUGprintf("__node_calloc: data calloc error\n");#elif defined FILE_DEBUG#endifgoto 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 <= 0){#ifdef DEBUGprintf("uolist_create: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0;} /* end of if (size <= 0 || NULL == my_destroy) *//* 申请头信息结构体空间 */uo = (uolist_t *)calloc(1, sizeof(uolist_t));if (NULL == uo){#ifdef DEBUGprintf("uolist_create: calloc error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_prepend: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_traverse: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_destroy: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("head_destroy: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("get_count: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_append: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 < 0){#ifdef DEBUGprintf("uolist_insert_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == uo || NULL == data || index < 0) *//* 1.创建一个新的节点 */temp1 = __node_calloc(uo);/* 2.节点数据输入 */temp1->next = NULL;memcpy(temp1->data, data, uo->size);/* 3.判断索引 */temp2 = uo->fstnode_p;if (index < uo->count && index > 0){// 寻找索引位置for (i = 0; i < index - 1; i++){temp2 = temp2->next;} /* end of for (i = 0; i < index; i++) */// 保存索引位置的链表save = temp2->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 < 0 || index >= uo->count){#ifdef DEBUGprintf("uolist_delete_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == uo || index < 0 || 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 < index - 1; i++){temp1 = temp1->next;} /* end of for (i = 0; i < index - 1; i++) */temp2 = temp1->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 < 0 || index >= uo->count || NULL == data){#ifdef DEBUGprintf("uolist_modify_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == uo || index < 0 || index >= uo->count || NULL == data) *//* 寻找索引位置 */temp = uo->fstnode_p;for (i = 0; i < index; i++){temp = temp->next;} /* end of for (i = 0; i < index; i++) *//* 修改数据 */memcpy(temp->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 < 0 || index >= uo->count || NULL == data){#ifdef DEBUGprintf("uolist_retrieve_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == uo || index < 0 || index >= uo->count || NULL == data) *//* 寻找索引位置 */temp = uo->fstnode_p;for (i = 0; i < index; i++){temp = temp->next;} /* end of for (i = 0; i < index; i++) *//* 修改数据 */memcpy(data, temp->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 DEBUGprintf("get_match_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_delete_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_modify_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_retrieve_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_delete_all_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_modify_all_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_find_all_index_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("uolist_reverse: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 <stdio.h>
#include "< name >.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 <= 10; 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个5temp = 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;
}
双向循环链表
拼图框架搭建 - Necessary
< name >.h
#ifndef __< name >_h__
#define __< name >_h__#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 匹配成功
#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
< name >.c
#include "< name >.h"/*** @brief 创建节点空间* @param 链表头信息结构体指针* @return 节点指针*/
static node_t *__node_calloc(udlist_t *ud)
{/* 变量定义 */node_t *p = NULL;/* 参数检查 */if (NULL == ud){#ifdef DEBUGprintf("__node_calloc: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == ud) *//* 创建节点空间 */ p = (node_t *)calloc(1, sizeof(node_t));if (NULL == p){#ifdef DEBUGprintf("__node_calloc: p calloc error\n");#elif defined FILE_DEBUG#endifgoto ERR1; } /* end of if (NULL == p) *//* 创建节点中数据空间 */p->data = (void *)calloc(1, ud->size);if (NULL == p->data){#ifdef DEBUGprintf("__node_calloc: data calloc error\n");#elif defined FILE_DEBUG#endifgoto 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 <= 0 || NULL == my_destroy){#ifdef DEBUGprintf("udlist_create: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0;} /* end of if (size <= 0 || NULL == my_destroy) *//* 申请头信息结构体空间 */ud = (udlist_t *)calloc(1, sizeof(udlist_t));if (NULL == ud){#ifdef DEBUGprintf("udlist_create: calloc error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_append: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_traverse: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_traverse_back: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_destroy: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("head_destroy: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("get_count: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 < 0){#ifdef DEBUGprintf("udlist_insert_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == ud || NULL == data || index < 0) *//* 判断索引 */temp2 = ud->fstnode_p;if (index < ud->count && index > 0){// 创建一个新的节点 temp1 = __node_calloc(ud);// 节点数据输入 temp1->next = temp1;temp1->prev = temp1;memcpy(temp1->data, data, ud->size);// 寻找索引位置for (i = 0; i < index - 1; i++){temp2 = temp2->next;} /* end of for (i = 0; i < index; i++) */// 保存索引位置的链表save = temp2->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 < 0 || index >= ud->count){#ifdef DEBUGprintf("udlist_delete_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == ud || index < 0 || 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 < index - 1; i++){temp1 = temp1->next;} /* end of for (i = 0; i < index - 1; i++) */temp2 = temp1->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 < 0 || index >= ud->count || NULL == data){#ifdef DEBUGprintf("udlist_modify_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == ud || index < 0 || index >= ud->count || NULL == data) *//* 寻找索引位置 */temp = ud->fstnode_p;for (i = 0; i < index; i++){temp = temp->next;} /* end of for (i = 0; i < index; i++) *//* 修改数据 */memcpy(temp->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 < 0 || index >= ud->count || NULL == data){#ifdef DEBUGprintf("udlist_retrieve_by_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto ERR0; } /* end of if (NULL == ud || index < 0 || index >= ud->count || NULL == data) *//* 寻找索引位置 */temp = ud->fstnode_p;for (i = 0; i < index; i++){temp = temp->next;} /* end of for (i = 0; i < index; i++) *//* 修改数据 */memcpy(data, temp->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 DEBUGprintf("get_match_index: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_delete_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_modify_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_retrieve_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_delete_all_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_modify_all_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 DEBUGprintf("udlist_find_all_index_by_key: Parameter error\n");#elif defined FILE_DEBUG#endifgoto 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 <stdio.h>
#include <stdlib.h>
#include <string.h>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 <= 10; temp++){// udlist_append(head, &temp);udlist_prepend(head, &temp);} /* end of for (temp = 1; temp <= 10; temp++) */// 遍历输出udlist_traverse(head, data_print);udlist_traverse_back(head, data_print);printf("cnt: %d\n", get_count(head));printf("====================================================\n");// 按照索引插入temp = 888;udlist_insert_by_index(head, &temp, 0);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 按照索引插入temp = 9090;udlist_insert_by_index(head, &temp, 200);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 按照索引插入temp = 77;udlist_insert_by_index(head, &temp, 7);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据索引删除udlist_delete_by_index(head, 3);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据索引修改temp = 100;udlist_modify_by_index(head, &temp, 0);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据索引获取udlist_retrieve_by_index(head, &temp, 5);// 输出printf("temp: %d\n", temp);printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据关键字删除int key = 100;udlist_delete_by_key(head, &key, data_compare);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据关键字修改temp = 3;key = 10;udlist_modify_by_key(head, &temp, &key, data_compare);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据关键字获取temp = 85;key = 4;udlist_retrieve_by_key(head, &temp, &key, data_compare);// 输出printf("temp: %d\n", temp);printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据关键字修改所有temp = 9;key = 3;// udlist_delete_all_by_key(head, &key, data_compare);udlist_modify_all_by_key(head, &temp, &key, data_compare);// 输出printf("cnt: %d\n", get_count(head));udlist_traverse(head, data_print);printf("====================================================\n");// 链表根据关键字查找所有索引key = 9;arr_index = udlist_find_all_index_by_key(head, &key, data_compare);// 输出printf("cnt: %d\n", get_count(arr_index));udlist_traverse(arr_index, index_print);printf("====================================================\n");// 释放udlist_destroy(head);head_destroy(&head);udlist_destroy(arr_index);head_destroy(&arr_index);return 0;
}
附录
符号 | 注解 |
---|---|
< name > | 将< name > 整体换成任意名称。 |
Necessary | 该标签标注的区域是必须阅读或者执行的,否则会导致功能异常。 |
Optional | 该标签标注的区域的阅读或者执行是可选的,忽略不会导致功能异常。 |
Dependent | 该标签标注的区域的阅读或者执行是可选的,但是它被某些功能所依赖时则必须添加。 |
相关文章:

【嵌入式高级C语言】9:万能型链表懒人手册
文章目录 序言单向不循环链表拼图框架搭建 - Necessary功能拼图块1 创建链表头信息结构体 - Necessary2 链表头部插入 - Optional3 链表的遍历 - Optional4 链表的销毁 - Necessary5 链表头信息结构体销毁 - Necessary6 获取链表中节点的个数 - Optional7 链表尾部插入 - Optio…...

如何快速分析OB集群日志,敏捷诊断工具obdiag分析能力实践——《OceanBase诊断系列》之四
1. 前言 obdiag是OceanBase的敏捷诊断工具。1.2版本中,obdiag支持快速收集诊断信息,但仅有收集能力是不够的,还需要有分析能力。因此在obdiag的1.3.0版本中,我们加入了OB集群的日志分析功能。用户可以一键进行集群的OB日志的分析…...

7.1.3 Selenium的用法2
目录 1. 切换 Frame 2. 前进后退 3. 对 Cookies 操作 4. 选项卡管理(了解) 5. 异常处理 6. 反屏蔽 7. 无头模式 1. 切换 Frame 我们知道网页中有一种节点叫作 iframe,也就是子 Frame,相当于页面的子页面,它的结构和外部网页的结构完全…...

微信小程序(五十四)腾讯位置服务示范(2024/3/8更新)
教程如下: 上一篇 1.先在官网注册一下账号(该绑定的都绑定一下) 腾讯位置服务官网 2.进入控制台 3.创建应用 3. 额度分配 4.下载微信小程序SDK 微信小程序SDK下载渠道 5.解压将俩js文件放在项目合适的地方 6.加入安全域名or设置不验证合…...

Selenium库快速查找网页元素及执行浏览器模拟操作
Selenium 是一个自动化测试工具,主要用于模拟用户在网页上的行为,进行自动化测试。它支持多种浏览器,并且可以在多种操作系统上运行。以下是 Selenium 库的一些主要特点和用途: 网页自动化测试: Selenium 可以模拟用户…...

2024年(第十届)全国大学生统计建模大赛选题参考(一)
本届大赛主题为“大数据与人工智能时代的统计研究”,参赛队围绕主题自拟题目撰写论文。 1. 大数据分析与处理 研究思路 数据收集:首先确定数据来源,例如社交媒体、企业数据库或公开数据集,并使用爬虫技术或API收集数据。数据预…...

EI级 | Matlab实现GCN基于图卷积神经网络的数据多特征分类预测
EI级 | Matlab实现GCN基于图卷积神经网络的数据多特征分类预测 目录 EI级 | Matlab实现GCN基于图卷积神经网络的数据多特征分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.GCN基于图卷积神经网络的数据分类预测 Matlab2023 2.多输入单输出的分类预测…...

贪心算法介绍
贪心算法是一种在求解问题时总是做出在当前看来是最好的选择的算法。它不从整体最优上加以考虑,所做出的选择只是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性…...

前端常用数据结构
前端常用数据结构 前端常用数据结构数据结构数组栈队列链表单向链表双向链表树前端常用数据结构 什么是数据结构常用的数据结构 JavaScript 如何实现这些数据结构实际场景数据结构 所谓数据结构,是在计算机中组织、管理和存储数据的一种方式。 🙋:你知道哪些数据结构? …...

java设计模式之——单例模式
一:什么是单例模式? 构造函数private之后,还需要提供一个方法,要保证只能初始化一个单例对象,并且需要考虑线程安全的问题。 二:单例模式多种写法? 具体到写法上,主要有5种&#…...

深入理解计算机系统学习笔记
1.1异常处理 处理器中很多事情都会导致异常控制流,此时,程序执行的正常流程被破坏掉。异常可以由程序执行从内部产生,也可以由某个外部信号从外部产 生。 我们的指令集体系结构包括三种不同的内部产生的异常: l)halt指令&#…...

Linux-进程信号
目录 概念信号产生信号注册信号注销信号处理实例 信号的基本应用 概念 进程信号: 概念:信号就是软件中断。信号就是用于向进程通知某个事件的产生,打断进程当前操作,去处理这个事件。 linux中信号的种类:使用kill -l命…...

Linux服务器安装jdk
背景: 安装JDK是我们java程序在服务器运行的必要条件,下面描述几个简单的命令就可再服务器上成功安装jdk 命令总览: yum update -y yum list | grep jdk yum -y install java-1.8.0-openjdk java -version 1.查看可安装版本 yum list | grep jdk 2.如果查不到可先进行 yum upd…...

基于 HBase Phoenix 构建实时数仓(2)—— HBase 完全分布式安装
目录 一、开启 HDFS 机柜感知 1. 增加 core-site.xml 配置项 2. 创建机柜感知脚本 3. 创建机柜配置信息文件 4. 分发相关文件到其它节点 5. 重启 HDFS 使机柜感知生效 二、主机规划 三、安装配置 HBase 完全分布式集群 1. 在所有节点上配置环境变量 2. 解压、配置环境…...

equals()与==的区别
在Java中 可以对基本类型进行比较,比较的是值是否相等 也可以对引用类型(对象)进行比较,比较的是引用变量所指向的空间地址 public static void main(String[] args) {int a 10;int b 10;System.out.println(ab);//true// 基本类型比较,比较值是否相等String s1 new Stri…...

什么是数据采集与监视控制系统(SCADA)?
SCADA数据采集是一种用于监控和控制工业过程的系统。它可以实时从现场设备获得数据并将其传输到中央计算机,以便进行监控和控制。SCADA数据采集系统通常使用传感器、仪表和控制器收集各种类型的数据,例如温度、压力、流量等,然后将这些数据汇…...

基于SpringBoot+Vue+ElementUI+Mybatis前后端分离管理系统超详细教程(五)——多条件搜索并分页展示
前后端数据交互 书接上文,我们上节课通过前后端数据交互实现了分页查询和单条件搜索分页查询的功能,最后留了个小尾巴,就是把其他两个搜索条件(email,address)也加进来,实现多条件搜索并分页展示。这节课我…...

鸿蒙实战开发Camera组件:【相机】
相机组件支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照和录像等。 基本概念 拍照 此功能用于拍摄采集照片。 预览 此功能用于在开启相机后,在缓冲区内重复采集…...

政安晨:【深度学习处理实践】(三)—— 处理时间序列的数据准备
在深度学习中,对时间序列的处理主要涉及到以下几个方面: 序列建模:深度学习可以用于对时间序列进行建模。常用的模型包括循环神经网络(Recurrent Neural Networks, RNN)和长短期记忆网络(Long Short-Term M…...

PCL不同格式点云读取速度(Binary和ASCII )
首先说明一点:Binary(二进制)格式点云文件进行读取时要比Ascll码格式点云读取时要快的多,尤其是对于大型的点云文件,如几百万、甚至几千万个点云的情况下。 今天遇到了一种情况,在写项目的时候进行点云读取,读取的时候…...

Neo4J图数据库入门示例
前言 - Neo4j和MySQL的区别 Neo4j 和 MySQL 是两种不同类型的数据库,它们在数据模型、用途、性能和查询语言等方面有着显著的区别。以下是它们的主要区别: 数据模型: Neo4j 是一种图数据库,它使用图数据模型来存储和查询数据。在…...

牛客每日一题之 二维前缀和
题目介绍: 题目链接:【模板】二维前缀和_牛客题霸_牛客网 先举两个简单的例子,来帮大家理解题目,注意理解二维前缀和要先要一维前缀和的基础,不了解的可以看我上一篇博客。 若x11,y11, x23, y2 3,这是要…...

动态规划 Leetcode 70 爬楼梯
爬楼梯 Leetcode 70 学习记录自代码随想录 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到…...

(未解决)macOS matplotlib 中文是方框
reference: Mac OS系统下实现python matplotlib包绘图显示中文(亲测有效)_mac plt 中文值-CSDN博客 module ‘matplotlib.font_manager‘ has no attribute ‘_rebuild‘解决方法_font_manager未解析-CSDN博客 # 问题描述(笑死 显而易见 # solve 找到…...

深入探讨C#中的递归算法
一、什么是递归算法? 递归是指一个函数或方法在执行过程中调用自身的情况。递归算法是编程中常见的一种解决问题的方法。它将一个问题分解成一个或多个与原问题相似但规模更小的子问题,然后通过解决这些子问题来解决原问题。递归算法通常用于解决重复性的…...

三款顶级开源RAG (检索增强生成)工具:Verba、Unstructured 和 Neum
三款顶级开源RAG (检索增强生成)工具:Verba、Unstructured 和 Neum 概述 随着企业对话式数据处理需求的提升,面临的挑战是数据隐私性和缺乏企业级解决方案。虽然类似LangChain能在短时间内构建RAG应用,但忽视了文档解析、多来源数据ETL、批量…...

VC++、MFC中操作excel时,CRange中get_EntireRow()和get_EntireColumn()函数的用法及区别是什么?
在VC和MFC中操作Excel时,通过COM接口与Excel交互时,CRange 对象(或更准确地说是 Excel::Range 对象)代表一个单元格范围。CRange 类提供了一系列方法来获取或操作这个范围内的单元格。其中,get_EntireRow() 和 get_Ent…...

npm 操作报错记录1- uninstall 卸载失效
npm 操作报错记录1- uninstall 卸载失效 1、问题描述 安装了包 vue/cli-plugin-eslint4.5.0 vue/eslint-config-prettier9.0.0 但是没有使用 -d ,所以想重新安装,就使用 uninstall 命令卸载,结果卸载了没反应,也没有报错…...

openCV保存图像
保存图像 //保存为png透明通道vector<int>opts;opts.push_back(IMWRITE_PAM_FORMAT_RGB_ALPHA);imwrite("D:/img_bgra.png", img, opts);//保存为单通道灰度图像img cv::imread(imagePath.toStdString(), IMREAD_GRAYSCALE);vector<int> opts_gray;opts…...

mac 配置.bash_profile不生效问题
1、问题描述 mac系统中配置了环境变量只能在当前终端生效,切换了终端就无效了,查了下问题所在。mac系统会预装一个终极shell - zsh,环境变量读取在 .zshrc 文件下。 2、解决方案 1、切换终端到bash 切换终端到bash chsh -s /bin/bash 切换终端…...