【嵌入式高级C语言】9:万能型链表懒人手册

news/2024/5/13 11:43:52/文章来源:https://blog.csdn.net/weixin_43256704/article/details/136542672

文章目录

  • 序言
  • 单向不循环链表
    • 拼图框架搭建 - `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.luyixian.cn/news_show_998998.aspx

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

相关文章

RFID-科技的“隐秘耳语者”

RFID-科技的“隐秘耳语者” 想象一下&#xff0c;你身处一个光线昏暗的环境中&#xff0c;周围的一切都被厚厚的阴影笼罩。这时&#xff0c;你需要识别并获取一个物体的信息&#xff0c;你会选择怎么做&#xff1f;是点亮灯光&#xff0c;用肉眼仔细观察&#xff0c;还是打开扫…

Haproxy实验搭建

1.yum本地源安装Haproxy [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 [rootlocalhost ~]# yum install haproxy -y2.yum网络源安装Haproxy 关闭防火墙和selinux ###先把安装包拖进来[rootlocalhost ~]# yum install rh-haproxy18-haproxy-1…

Linux操作系统的vim常用命令和vim 键盘图

在vi编辑器的命令模式下&#xff0c;命令的组成格式是&#xff1a;nnc。其中&#xff0c;字符c是命令&#xff0c;nn是整数值&#xff0c;它表示该命令将重复执行nn次&#xff0c;如果不给出重复次数的nn值&#xff0c;则命令将只执行一次。例如&#xff0c;在命令模式下按j键表…

[java基础揉碎]继承

为什么需要继承: > 继承就可以解决代码复用的问题 继承的基本介绍: 继承的使用细节: 1.子类继承了所有的属性和方法&#xff0c;但是私有属性和方法不能在子类直接访问&#xff0c;要通过公共的方法去访问 解决, 提供公共的方法返回: 2.子类必须调用父类的构造器,完成父…

Linux系统——LVS、Nginx、HAproxy区别

目录 一、LVS 1.负载均衡机制 1.1负载均衡——NAT模式 1.2负载均衡——DR模式 1.3负载均衡——隧道模式 1.4负载均衡——总结 2.LVS调度算法 3.LVS优点 4.LVS缺点 二、Nginx 1.传统基于进程或线程的模型 2.Nginx架构设计 3.Nginx负载均衡 4.Nginx调度算法 5.Ngi…

Jmeter 测试使用基本组件结构

JMeter简介 Apache组织开发的开源免费压测工具纯Java程序&#xff0c;跨平台性强源程序可以从网上下载高扩展性可对服务器、网络或对象模拟巨大的负载&#xff0c;进行压力测试可以用于接口测试支持分布式、多节点部署 JMeter安装 下载位置 官网https://jmeter.apache.org/ …

Java中SpringBoot四大核心组件是什么

一、Spring Boot Starter 1.1 Starter的应用示例 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency><groupId>org.mybatis.sprin…

深度学习与人类的智能交互:迈向自然与高效的人机新纪元

引言 随着科技的飞速发展&#xff0c;深度学习作为人工智能领域的一颗璀璨明珠&#xff0c;正日益展现出其在模拟人类认知和感知过程中的强大能力。本文旨在探讨深度学习如何日益逼近人类智能的边界&#xff0c;并通过模拟人类的感知系统&#xff0c;使机器能更深入地理解和解…

高级语言讲义2016计专(仅高级语言部分)

1.斐波那契序列的第n项可以表示成以下形式&#xff0c;编写一个非递归函数&#xff0c;返回该数列的第n项的数值 #include <stdio.h>int func(int n) {if(n1||n2)return 1;int p1,q1,num;for(int i3; i<n; i) {numpq;qp;pnum;}return num; } 2.在MXN的二维数组A中&am…

瑞_23种设计模式_模板方法模式

文章目录 1 模板方法模式&#xff08;Template Pattern&#xff09; ★ 钩子函数1.1 介绍1.2 概述1.3 模板方法模式的结构1.4 模板方法模式的优缺点1.5 模板方法模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析&#xff08;InputStre…

【测试工具系列】压测用Jmeter还是LoadRunner?还是其他?

说起JMeter&#xff0c;估计很多测试人员都耳熟能详。它小巧、开源&#xff0c;还能支持多种协议的接口和性能测试&#xff0c;所以在测试圈儿里很受欢迎&#xff0c;也是测试人员常用的工具&#xff0c;但是在企业级性能场景下可能会有性能瓶颈&#xff0c;更适合测试自己使用…

Grafana二次开发环境搭建

1 Grafana环境搭建 1.1 搭建后端服务 下载windows安装版文件grafana.com 1&#xff09;选择版本号&#xff1a;此处我选的8.3.3版本 2&#xff09;安装完成后&#xff0c;请记住安装目录 &#xff0c;我的是在 D:\software\Gragana833 安装完成后会自动运行, 3&#xff09;此…

2024年软考重大改革

中国计算机技术职业资格网 考试日期 考试级别 考试资格名称 5月25日至28日 高级 系统分析师 系统架构设计师 信息系统项目管理师 中级 软件设计师 网络工程师 软件评测师 电子商务设计师 嵌入式系统设计师 数据库系统工程师 信息系统管理工程师 初级 程序员 …

MySQL之体系结构和基础管理

前言 本文以linux系统的MySQL为例详细介绍MySQL的体系结构&#xff0c;因为在实际生产环境中MySQL的运行环境都是linux系统。同时介绍MySQL的基础管理&#xff0c;包括用户管理和权限管理等。 MySQL体系结构 MySQL客户端/服务器工作模型 MySQL是C/S架构&#xff0c;工作模型…

物联网,智慧城市的数字化转型引擎

随着科技的飞速发展&#xff0c;物联网&#xff08;IoT&#xff09;已成为推动智慧城市建设的关键力量。物联网技术通过连接各种设备和系统&#xff0c;实现数据的实时采集、传输和处理&#xff0c;为城市的智能化管理提供了强大的支持。在数字化转型的浪潮中&#xff0c;物联网…

VUE_nuxt启动只能通过localhost访问,ip访问不到:问题解决

修改项目根目录下的 package.json "config": {"nuxt": {"host": "0.0.0.0","port": "3000"} } 这样项目启动后就可以通过ip进行访问了

AutoDev 自定义 Agent:快速接入内部 AI Agent,构建 IDE 即 AI 辅助研发中心

在开源 AI IDE 插件 AutoDev 的 #51 issue 中&#xff0c;我们设计了 AutoDev 的 AI Agent 能力&#xff0c;半年后我们终于交付了这个功能。 在 AutoDev 1.7.0 中&#xff0c;你将可以接入内部的 AI Agent&#xff0c;并将其无缝与现有的 AI 辅助能力结合在一起。 本文将使用 …

使用awk和正则表达式过滤文本或字符串 - 详细指南和示例

当我们在 Linux 中运行某些命令来读取或编辑字符串或文件中的文本时&#xff0c;我们经常尝试将输出过滤到感兴趣的特定部分。这就是使用正则表达式派上用场的地方。 什么是正则表达式&#xff1f; 正则表达式可以定义为表示多个字符序列的字符串。关于正则表达式最重要的事情之…

【C++ STL详解】——string类

目录 前言 一、string类对象的常见构造 二、string类对象的访问及遍历 1.下标【】&#xff08;底层operator【】函数&#xff09; ​编辑 2.迭代器 3.范围for 4.at 5.back和front 三、string类对象的容量操作 1.size 和 length 2.capacity 3.empty 4.clear 5.res…

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

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