【嵌入式高级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`
    • 测试代码分享
  • 附录

序言

本链表篇意在制作所有人都可拿来即用的万能型链表懒人拼装手册,使用门槛低,不需要使用者有很深的语言和数据结构理解,使用简单且有参考代码。如使用本手册进行链表的学习也是一种绝佳的体验,源码注释丰富且逻辑清晰,相信读者可以在轻松愉快的环境下学习掌握。如果全部理解并掌握此手册,相信你对于绝大部分链表及数据操作已然不成问题,借此打下良好的基础便于日后面对更加复杂的挑战。

万能型链表义如其名,可以存储任何数据类型,只有你想不到的,没有它存不了的,但是需要读者注意其使用技巧(必要时请参考附录)。

在开始前,本人在这里借用戴尔·卡耐基的一句话祝各位学习路上可以披荆斩棘,乘风破浪,一往直前。

多数人都拥有自己不了解的能力和机会,都有可能做到未曾梦想的事情。
——戴尔·卡耐基

单向不循环链表

image.png

拼图框架搭建 - 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;        
}

使用此功能同时需要添加912功能。

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; 
}

使用此功能同时需要添加1012功能。

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; 
}

使用此功能同时需要添加1112功能。

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;  }

使用此功能同时需要添加912功能。

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; 
}

使用此功能同时需要添加1012功能。

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){}

image.png

2 自定义数据打印函数 - Necessary

int data_print(void *data){}

image.png

3 自定义数据比较函数 - Necessary

int data_compare(void *data, void *key){}

image.png

测试代码参考

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;
}

双向循环链表

image.png

拼图框架搭建 - 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; 
}

使用此功能需要添加32功能。

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;        
}

使用此功能同时需要添加1013功能。

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; 
}

使用此功能同时需要添加1113功能。

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; 
}

使用此功能同时需要添加1213功能。

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;  }

使用此功能同时需要添加1013功能。

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; 
}

使用此功能同时需要添加1113功能。

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){}

image.png

2 自定义数据打印函数 - Necessary

int data_print(void *data){}

image.png

3 自定义数据比较函数 - Necessary

int data_compare(void *data, void *key){}

image.png

测试代码分享

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该标签标注的区域的阅读或者执行是可选的,但是它被某些功能所依赖时则必须添加。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/271955.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git克隆过程报错

设置 git config 来强制 git 使用 HTTP 1.1 git config --global http.version HTTP/1.1想将其设置回 HTTP2&#xff0c;你可以这样做 git config --global http.version HTTP/2

飞驰云联CEO朱旭光荣获“科技领军人才”称号

2024年2月29日&#xff0c;苏州工业园区“优化营商环境暨作风效能建设大会”成功举办&#xff0c;会上公布了2023年度苏州工业园区第十七届第一批金鸡湖科技领军人才名单&#xff0c;Ftrans飞驰云联创始人兼CEO朱旭光先生凭借在数据安全以及文件交换领域取得的突出成果&#xf…

Feign实现微服务间远程调用续;基于Redis实现消息队列用于延迟任务的处理,Redis分布式锁的实现;(黑马头条Day05)

目录 延迟任务和定时任务 使用Redis设计延迟队列原理 点评项目中选用list和zset两种数据结构进行实现 如何缓解Redis内存的压力同时保证Redis中任务能够被正确消费不丢失 系统流程设计 使用Feign实现微服务间的任务消费以及文章自动审核 系统微服务功能介绍 提交文章-&g…

【k8s管理--两种方式安装prometheus】

1、k8s的监控方案 1.1 Heapster Heapster是容器集群监控和性能分忻工具&#xff0c;天然的支持Kubernetes和CoreOS。 Kubernetes有个出名的监控agent–cAdvisor。在每个kubernetes Node上都会运行cAdvisor&#xff0c;它会收集本机以及容器的监控数(cpu,memory,filesystem,ne…

【.NET Core】深入理解IO - FileSteam流

【.NET Core】深入理解IO - FileSteam流 文章目录 【.NET Core】深入理解IO - FileSteam流一、IO流概述二、文件流FileStream2.1 FileStream概述2.2 FileStream检测流位置更改2.3 FileStream构造函数2.4 FileStream常用属性2.5 FileStream.Read方法2.6 FileStream.Write方法2.7…

尚硅谷JavaScript高级学习笔记

01 准备 JavaScript中函数是对象。我们后续描述构造函数的内存模型时&#xff0c;会将构造函数称为构造函数对象。 02 数据类型 typeof 运算符来查看值的类型&#xff0c;它返回的是类型的字符串值 会做数据转换 03 相关问题 04数据_变量_内存 05相关问题1 06相关问题2 …

植物病虫害:YOLO玉米病虫害识别数据集

玉米病虫害识别数据集&#xff1a;玉米枯萎病&#xff0c;玉米灰斑病&#xff0c;玉米锈病叶&#xff0c;粘虫幼虫&#xff0c;玉米条斑病&#xff0c;黄二化螟&#xff0c;黄二化螟幼虫7类&#xff0c;yolo标注完整&#xff0c;3900多张图像&#xff0c;全部原始数据&#xff…

学习人工智能:吴恩达《AI for everyone》2019 第4周:歧视,攻击,发展中国家,就业

吴恩达 Andrew Ng&#xff0c; 斯坦福大学前教授&#xff0c;Google Brain项目发起人、领导者。 Coursera 的联合创始人和联合主席&#xff0c;在 Coursera 上有十万用户的《机器学习》课程&#xff1b;斯坦福大学计算机科学前教授。百度前副总裁、前首席科学家&#xff1b;谷…

WPF 消息提示 类似toast方式

WPF里面的消息提示一般都是MessageBox.Show()&#xff0c;这种样式不是很好看&#xff0c;所以就想办法重新搞了一个类似弹出消息的功能。原理很简单&#xff0c;就是弹出一个新窗体&#xff0c;然后等几秒窗体自动关闭。 先上效果图&#xff1a; 新建一个MsgHelper.cs类&…

Linux文件与文件系统的压缩

文章目录 Linux文件与文件系统的压缩Linux系统常见的压缩命令gzip&#xff0c;zcat/zmore/zless/zgrepbzip2&#xff0c;bzcat/bzmore/bzless/bzgreppxz&#xff0c;xzcat/xzmore/xzless/xzgrepgzip&#xff0c;bzip2&#xff0c;xz压缩时间对比打包命令&#xff1a;tar打包命令…

window vscode安装node.js

window vscode安装node.js 官网下好vscode 和nodejs 选.msi的安装 点这个安装 下载完 继续安装 完毕后倒杯水喝个茶等2分钟 重启VScode 或者在cmd 运行 npm -v node -v 显示版本号则成功

Prompt进阶系列1:LangGPT(从编程语言反思LLM的结构化可复用提示设计框架)

Prompt进阶系列1:LangGPT(从编程语言反思LLM的结构化可复用提示设计框架) 大语言模型 (Large Language Models, LLMs) 在不同领域都表现出了优异的性能。然而&#xff0c;对于非AI专家来说&#xff0c;制定高质量的提示来引导 LLMs 是目前AI应用领域的一项重要挑战。现有的提示…

Flink 物理执行图

文章目录 物理执行图一、Task二、ResultPartition三、ResultSubpartition四、InputGate五、InputChannel 物理执行图 JobManager根据ExecutionGraph对作业进行调度&#xff0c;并在各个TaskManager上部署任务。这些任务在TaskManager上的实际执行过程就形成了物理执行图。物理…

【目标检测实验系列】AutoDL线上GPU服务器租用流程以及如何用Pycharm软件远程连接服务器进行模型训练 (以Pycharm远程训练Yolov5项目为例子 超详细)

目录 1. 文章主要内容2. 租用AutoDL服务器详细教程2.1 注册AutoDL账号&#xff0c;并申请学生认证(学生认证有优惠&#xff0c;如果不是学生可以忽略此点)2.2 算力市场选择GPU&#xff0c;并选择初始化配置环境2.3 控制台参数解析&#xff0c;并使用相关参数登录Xftp(Windows与…

【蓝桥杯】k倍区间

一.题目描述 二.问题分析 对于该问题&#xff0c;标签上写的是暴力&#xff0c;但是如果使用暴力的话&#xff0c;会超时。 首先&#xff0c;对于两个数a&#xff0c;b&#xff08;假设a小于b&#xff09;&#xff0c;若a与b对k取余后结果相同&#xff0c;则b-a可以整除k。 …

ubuntu 卸载miniconda3

一开始安装路径错了&#xff0c;需要重新安一次&#xff0c;就一起记录了。 前提是这种方式安装&#xff1a; ubuntu安装miniconda3管理python版本-CSDN博客 删除Miniconda的安装目录 这目录就是你选择安装的时候指定的&#xff0c;如果记不得了,可以这样查看 which conda 这…

flink重温笔记(十二): flink 高级特性和新特性(1)——End-to-End Exactly-Once(端到端精确一致性语义)

Flink学习笔记 前言&#xff1a;今天是学习 flink 的第 12 天啦&#xff01;学习了 flink 高级特性和新特性之 End-to-End Exactly-Once&#xff08;端到端精确一致性语义&#xff09;&#xff0c;主要是解决大数据领域数据从数据源到数据落点的一致性&#xff0c;不会容易造成…

Python编程实验六:面向对象应用

目录 一、实验目的与要求 二、实验内容 三、主要程序清单和程序运行结果 第1题 第2题 四、实验结果分析与体会 一、实验目的与要求 &#xff08;1&#xff09;通过本次实验&#xff0c;学生应掌握类的定义与对象的创建、类的继承与方法的覆盖&#xff1b; &#xff08;2…

基于SSM技术的分布式销售平台设计与实现

目 录 摘 要 I Abstract II 1 绪论 1 1.1 课题研究背景与意义 1 1.2 国内外研究现状 1 1.2.1 国外研究现状 1 1.2.2 国内研究现状 2 1.3 本章小结 2 2 工程开发技术介绍 3 2.1 Web前端技术栈 3 2.1.1 HTML&CSS 3 2.1.2 jQuery 3 2.1.3 JSP 3 2.2 服务端开发技术栈 3 2.2.1…

【Linux】第一个小程序--进度条

这篇博客要综合利用以前的知识&#xff0c;来实现一个进度条程序~ 目录 换行&回车 缓冲区 实现简单的倒计时 实现进度条 version1 version2 在开始写这个小程序之前&#xff0c;我们先学习一些预备知识&#xff1a; 换行&回车 缓冲区 在我们运行这个程序时&…