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

news2024/11/19 18:18:20

文章目录

  • 序言
  • 单向不循环链表
    • 拼图框架搭建 - `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 DEBUG
        printf("__node_calloc: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;  
    } /* end of if (NULL == uo) */

    /* 创建节点空间 */ 
    p = (node_t *)calloc(1, sizeof(node_t));
    if (NULL == p)
    {
    #ifdef DEBUG
        printf("__node_calloc: p calloc error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR1;  
    } /* end of if (NULL == p) */

    /* 创建节点中数据空间 */
    p->data = (void *)calloc(1, uo->size);
    if (NULL == p->data)
    {
    #ifdef DEBUG
        printf("__node_calloc: data calloc error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR2;          
    } /* end of if (NULL == p->data) */

    return p;

ERR0:
    return (void *)PAR_ERROR;
ERR2:
    free(p);
    p = NULL;
ERR1:
    return (void *)FUN_ERROR;
}

/****************************************请在下方添加功能块拼图************************************************/



功能拼图块

1 创建链表头信息结构体 - Necessary

.h功能添加区

/**
 * @brief           创建链表头信息结构体
 * @param           存储数据类型大小
 * @param           自定义销毁数据函数
 * @return          指向链表头信息结构体的指针
 */
uolist_t *uolist_create(int size, op_t my_destroy);

.c功能添加区

/**
 * @brief           创建链表头信息结构体
 * @param           存储数据类型大小
 * @param           自定义销毁数据函数
 * @return          指向链表头信息结构体的指针
 */
uolist_t *uolist_create(int size, op_t my_destroy)
{
    /* 变量定义 */
    uolist_t *uo = NULL;

    /* 参数检查 */
    if (size <= 0)
    {
    #ifdef DEBUG
        printf("uolist_create: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;
    } /* end of if (size <= 0 || NULL == my_destroy) */


    /* 申请头信息结构体空间 */
    uo = (uolist_t *)calloc(1, sizeof(uolist_t));
    if (NULL == uo)
    {
    #ifdef DEBUG
        printf("uolist_create: calloc error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR1;       
    } /* end of if (NULL == uo) */

    /* 信息输入 */
    uo->count = 0;
    uo->size = size;
    uo->fstnode_p = NULL;
    uo->my_destroy = my_destroy;


    return uo;

ERR0:
    return (void *)PAR_ERROR;
ERR1:
    return (void *)FUN_ERROR;
}

2 链表头部插入 - Optional

.h功能添加区

/**
 * @brief           链表头部插入
 * @param           头信息结构体的指针
 * @param           插入节点数据
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_prepend(uolist_t *uo, void *data);

.c功能添加区

/**
 * @brief           链表头部插入
 * @param           头信息结构体的指针
 * @param           插入节点数据
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_prepend(uolist_t *uo, void *data)
{
    node_t *temp1 = NULL;
    node_t *temp2 = NULL;

    /* 参数检查 */
    if (NULL == uo || NULL == data)
    {
    #ifdef DEBUG
        printf("uolist_prepend: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == data) */

    /* 1.创建一个新的节点 */
    temp1 = __node_calloc(uo);

    /* 2.节点数据输入 */
    temp1->next = NULL;
    memcpy(temp1->data, data, uo->size);


    /* 3.链表节点头部插入 */
    if (NULL == uo->fstnode_p)
    {
        uo->fstnode_p = temp1;
    }
    else 
    {
        temp2 = uo->fstnode_p;
        uo->fstnode_p = temp1;
        temp1->next = temp2;
    }

    /* 链表头信息更新 */
    uo->count++;

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;
}

3 链表的遍历 - Optional

.h功能添加区

/**
 * @brief           链表的遍历
 * @param           头信息结构体的指针
 * @param           自定义打印数据函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_traverse(uolist_t *uo, op_t my_print);

.c功能添加区

/**
 * @brief           链表的遍历
 * @param           头信息结构体的指针
 * @param           自定义打印数据函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_traverse(uolist_t *uo, op_t my_print)
{
    node_t *temp = NULL;

    /* 参数检查 */
    if (NULL == uo || NULL == my_print)
    {
    #ifdef DEBUG
        printf("uolist_traverse: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == my_print) */



    /* 链表的遍历 */
    temp = uo->fstnode_p;
    while (temp != NULL)
    {
        my_print(temp->data);
        temp = temp->next;
    } /* end of while (temp != NULL) */


    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;    
}

4 链表的销毁 - Necessary

.h功能添加区

/**
 * @brief           链表销毁函数(不包括头信息结构体)
 * @param           头信息结构体的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_destroy(uolist_t *uo);

.c功能添加区

/**
 * @brief           链表销毁函数(不包括头信息结构体)
 * @param           头信息结构体的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_destroy(uolist_t *uo)
{
    node_t *temp = NULL;
    node_t *save = NULL;

    /* 参数检查 */
    if (NULL == uo)
    {
    #ifdef DEBUG
        printf("uolist_destroy: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo) */    

    temp = uo->fstnode_p;

    /* 依次释放节点空间 */
    while (NULL != temp)
    {
        /* 1.保存下个节点的指针 */
        save = temp->next;

        /* 2.释放数据空间 */
        uo->my_destroy(temp->data);
        temp->data = NULL;

        /* 3.释放节点空间 */
        free(temp);
        temp = NULL;

        /* 4.指向下一个节点 */
        temp = save;
    } /* end of while (NULL != temp) */

    /* 头信息刷新 */
    uo->fstnode_p = NULL;
    uo->count = 0;

    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;     
}

5 链表头信息结构体销毁 - Necessary

.h功能添加区

/**
 * @brief           头信息结构体销毁函数
 * @param           头信息结构体的指针的地址
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int head_destroy(uolist_t **p);

.c功能添加区

/**
 * @brief           头信息结构体销毁函数
 * @param           头信息结构体的指针的地址
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int head_destroy(uolist_t **p)
{
    /* 参数检查 */
    if (NULL == p)
    {
    #ifdef DEBUG
        printf("head_destroy: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == p) */  

    /* 销毁结构体空间 */
    free(*p);
    *p = NULL;

    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;  
}

6 获取链表中节点的个数 - Optional

.h功能添加区

/**
 * @brief           获取链表中节点的个数
 * @param           头信息结构体的指针
 * @return          链表节点个数
 */
int get_count(uolist_t *p);

.c功能添加区

/**
 * @brief           获取链表中节点的个数
 * @param           头信息结构体的指针
 * @return          链表节点个数
 */
int get_count(uolist_t *p)
{

    /* 参数检查 */
    if (NULL == p)
    {
    #ifdef DEBUG
        printf("get_count: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == p) */  

    return p->count;

ERR0:
    return PAR_ERROR;
}

7 链表尾部插入 - Optional/Dependent

.h功能添加区

/**
 * @brief           链表尾部插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_append(uolist_t *uo, void *data);

.c功能添加区

/**
 * @brief           链表尾部插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_append(uolist_t *uo, void *data)
{
    node_t *temp1 = NULL;
    node_t *temp2 = NULL;

    /* 参数检查 */
    if (NULL == uo || NULL == data)
    {
    #ifdef DEBUG
        printf("uolist_append: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == data) */

    /* 1.创建一个新的节点 */
    temp1 = __node_calloc(uo);

    /* 2.节点数据输入 */
    temp1->next = NULL;
    memcpy(temp1->data, data, uo->size);

    /* 3.数据尾部插入 */
    if (NULL == uo->fstnode_p)
    {
        uo->fstnode_p = temp1;
    }
    else 
    {
        temp2 = uo->fstnode_p;
        while (temp2->next != NULL)
        {
            temp2 = temp2->next;
        } /* end of while (temp2->next != NULL) */

        temp2->next = temp1;
    }

    /* 4.刷新信息 */
    uo->count++;

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;  

}

8 链表根据索引插入数据 - Optional

.h功能添加区

/**
 * @brief           链表根据索引插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @param           索引值
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_insert_by_index(uolist_t *uo, void *data, int index);

.c功能添加区

/**
 * @brief           链表根据索引插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @param           索引值
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_insert_by_index(uolist_t *uo, void *data, int index)
{
    node_t *temp1 = NULL;
    node_t *temp2 = NULL;
    node_t *save = NULL;
    int i = 0;


    /* 参数检查 */
    if (NULL == uo || NULL == data || index < 0)
    {
    #ifdef DEBUG
        printf("uolist_insert_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("uolist_delete_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("uolist_modify_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("uolist_retrieve_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("get_match_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */


    /* 判断是否为空链表 */
    if (NULL == uo->fstnode_p)
    {
        goto ERR1;
    } /* end of if (NULL == uo->fstnode_p) */

    /* 寻找匹配索引 */
    index = 0;
    temp = uo->fstnode_p;
    while (1)
    {
        if (MATCH_SUCCESS == op_cmp(temp->data, key))
        {
            return index;
        } /* end of if (MATCH_SUCCESS == op_cmp(temp->data, key)) */

        temp = temp->next;
        if (NULL == temp)
        {
            goto ERR1;
        } /* end of if (NULL == temp) */
        index++;
    } /* end of while (1) */


ERR0:
    return PAR_ERROR;
ERR1:
    return MATCH_FAIL; 
}

13 链表根据关键字删除数据 - Optional

.h功能添加区

/**
 * @brief           链表根据关键字删除
 * @param           头信息结构体的指针
 * @param           关键字
 * @param           自定义比较函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_delete_by_key(uolist_t *uo, void *key, cmp_t op_cmp);

.c功能添加区

/**
 * @brief           链表根据关键字删除
 * @param           头信息结构体的指针
 * @param           关键字
 * @param           自定义比较函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int uolist_delete_by_key(uolist_t *uo, void *key, cmp_t op_cmp)
{
    int index = 0;

    /* 参数检查 */
    if (NULL == uo || NULL == key || NULL == op_cmp)
    {
    #ifdef DEBUG
        printf("uolist_delete_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */


    /* 获取匹配索引 */
    index = get_match_index(uo, key, op_cmp);
    if (PAR_ERROR == index || MATCH_FAIL == index)
    {
        goto ERR1;
    } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


    /* 根据索引删除节点 */
    uolist_delete_by_index(uo, index);


    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;        
}

使用此功能同时需要添加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 DEBUG
        printf("uolist_modify_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) */


    /* 获取匹配索引 */
    index = get_match_index(uo, key, op_cmp);
    if (PAR_ERROR == index || MATCH_FAIL == index)
    {
        goto ERR1;
    } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


    /* 根据索引修改数据 */
    uolist_modify_by_index(uo, data, index);


    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR; 
}

使用此功能同时需要添加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 DEBUG
        printf("uolist_retrieve_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) */


    /* 获取匹配索引 */
    index = get_match_index(uo, key, op_cmp);
    if (PAR_ERROR == index || MATCH_FAIL == index)
    {
        goto ERR1;
    } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */

    /* 根据索引获取数据 */
    uolist_retrieve_by_index(uo, data, index);

    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR; 
}

使用此功能同时需要添加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 DEBUG
        printf("uolist_delete_all_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */

    while (1)
    {
        /* 获取匹配索引 */
        index = get_match_index(uo, key, op_cmp);
        if (PAR_ERROR == index || MATCH_FAIL == index)
        {
            goto ERR1;
        } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


        /* 根据索引删除节点 */
        uolist_delete_by_index(uo, index);

    } /* end of while (1) */

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;  

}

使用此功能同时需要添加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 DEBUG
        printf("uolist_modify_all_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp || NULL == data) */

    while (1)
    {
        /* 获取匹配索引 */
        index = get_match_index(uo, key, op_cmp);
        if (PAR_ERROR == index || MATCH_FAIL == index)
        {
            goto ERR1;
        } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


        /* 根据索引修改数据 */
        uolist_modify_by_index(uo, data, index);

    } /* end of while (1) */

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR; 
}

使用此功能同时需要添加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 DEBUG
        printf("uolist_find_all_index_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo || NULL == key || NULL == op_cmp) */


    /* 判断链表是否存在 */
    if (NULL == uo->fstnode_p)
    {
        goto ERR1;
    } /* end of if (NULL == uo->fstnode_p) */


    /* 创建存储索引的链表头信息结构体 */
    index_head = uolist_create(sizeof(int), index_destroy);


    /* 查找索引并插入链表 */
    temp = uo->fstnode_p;
    for (index = 0; NULL != temp; index++, temp = temp->next)
    {
        if (MATCH_SUCCESS == op_cmp(temp->data, key))
        {
            uolist_append(index_head, &index);
        }
    } /* end of for (index = 0; NULL != temp; index++, temp = temp->next) */


    /* 判断是否为空链表 */
    if (0 == get_count(index_head))
    {
        head_destroy(&index_head);
    } /* end of if (0 == get_count(index_head)) */


    return index_head;


ERR0:
    return (void *)PAR_ERROR;
ERR1:
    return NULL;
}

/**
 * @brief           自定义索引销毁函数
 * @param           数据域
 * @return          0
 */
int index_destroy(void *data)
{
    free(data);
    data = NULL;
    return 0;
}


/**
 * @brief           自定义索引打印函数
 * @param           数据域
 * @return          0
 */
int index_print(void *data)
{
    printf("index = %d\n", *(int *)data);
    return 0;
}

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

19 链表的翻转 - Optional

.h功能添加区

/**
 * @brief           链表的翻转
 * @param           头信息结构体的指针
 * @return          
 *      @arg  PAR_ERROR: 参数错误
 *      @arg  0        : 正常
 */
int uolist_reverse(uolist_t *uo);

.c功能添加区

/**
 * @brief           链表的翻转
 * @param           头信息结构体的指针
 * @return          
 *      @arg  PAR_ERROR: 参数错误
 *      @arg  0        : 正常
 */
int uolist_reverse(uolist_t *uo)
{
    node_t *p = NULL;
    node_t *save = NULL;
    node_t *temp = NULL;

    /* 参数检查 */
    if (NULL == uo)
    {
    #ifdef DEBUG
        printf("uolist_reverse: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == uo) */

    /* 链表的翻转 */
    for (p = uo->fstnode_p, uo->fstnode_p = NULL, uo->count = 0; NULL != p; p = save)
    {
        /* 保存下一个节点 */
        save = p->next;

        /* 链表头插 */
        p->next = NULL;
        if (NULL == uo->fstnode_p)
        {
            uo->fstnode_p = p;
        }
        else 
        {
            temp = uo->fstnode_p;
            uo->fstnode_p = p;
            p->next = temp;
        }

        /* 链表头信息更新 */
        uo->count++;
    } /* end of for (p = uo->fstnode_p, uo->fstnode_p = NULL, uo->count = 0; NULL != p; p = save) */

    return 0;


ERR0:
    return PAR_ERROR;


}

测试代码添加模块

1 自定义数据销毁函数 - Necessary

int node_destroy(void *data){}

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个5
    temp = 5;
    uolist_append(head, &temp);
    uolist_append(head, &temp);
    uolist_append(head, &temp);

    // 链表的遍历
    printf("count = %d\n", get_count(head));
    uolist_traverse(head, data_print);
    printf("==================================================\n");

    // 链表根据关键字查找所有的索引
    key = 5;
    index = uolist_find_all_index_by_key(head, &key, data_compare);

    // 索引链表的遍历
    printf("count = %d\n", get_count(index));
    uolist_traverse(index, index_print);
    printf("==================================================\n");

    // 链表根据关键字修改所有的节点
    temp = 555;
    key = 5;
    uolist_modify_all_by_key(head, &temp, &key, data_compare);

    // 链表的遍历
    printf("count = %d\n", get_count(head));
    uolist_traverse(head, data_print);
    printf("==================================================\n");

    // 链表根据关键字删除所有的节点
    key = 555;
    uolist_delete_all_by_key(head, &key, data_compare);

    // 链表的遍历
    printf("count = %d\n", get_count(head));
    uolist_traverse(head, data_print);
    printf("==================================================\n");

    // 链表的翻转
    uolist_reverse(head);

    // 链表的遍历
    printf("count = %d\n", get_count(head));
    uolist_traverse(head, data_print);
    printf("==================================================\n");

    // 链表的释放
    uolist_destroy(head);
    uolist_destroy(index);
    head_destroy(&head);
    head_destroy(&index);

    return 0;
}

双向循环链表

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 DEBUG
        printf("__node_calloc: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;  
    } /* end of if (NULL == ud) */

    /* 创建节点空间 */ 
    p = (node_t *)calloc(1, sizeof(node_t));
    if (NULL == p)
    {
    #ifdef DEBUG
        printf("__node_calloc: p calloc error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR1;  
    } /* end of if (NULL == p) */

    /* 创建节点中数据空间 */
    p->data = (void *)calloc(1, ud->size);
    if (NULL == p->data)
    {
    #ifdef DEBUG
        printf("__node_calloc: data calloc error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR2;          
    } /* end of if (NULL == p->data) */


    return p;

ERR0:
    return (void *)PAR_ERROR;
ERR2:
    free(p);
    p = NULL;
ERR1:
    return (void *)FUN_ERROR;
}

/****************************************请在下方添加功能块拼图************************************************/



功能拼图块

1 创建链表头信息结构体 - Necessary

.h功能添加区

/**
 * @brief           创建链表头信息结构体
 * @param           存储数据类型大小
 * @param           自定义销毁数据函数
 * @return          指向链表头信息结构体的指针
 */
udlist_t *udlist_create(int size, op_t my_destroy);

.c功能添加区

/**
 * @brief           创建链表头信息结构体
 * @param           存储数据类型大小
 * @param           自定义销毁数据函数
 * @return          指向链表头信息结构体的指针
 */
udlist_t *udlist_create(int size, op_t my_destroy)
{
    /* 变量定义 */
    udlist_t *ud = NULL;

    /* 参数检查 */
    if (size <= 0 || NULL == my_destroy)
    {
    #ifdef DEBUG
        printf("udlist_create: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;
    } /* end of if (size <= 0 || NULL == my_destroy) */


    /* 申请头信息结构体空间 */
    ud = (udlist_t *)calloc(1, sizeof(udlist_t));
    if (NULL == ud)
    {
    #ifdef DEBUG
        printf("udlist_create: calloc error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR1;       
    } /* end of if (NULL == ud) */

    /* 信息输入 */
    ud->count = 0;
    ud->size = size;
    ud->fstnode_p = NULL;
    ud->my_destroy = my_destroy;


    return ud;

ERR0:
    return (void *)PAR_ERROR;
ERR1:
    return (void *)FUN_ERROR;
}

2 链表头部插入 - Optional/Dependent

.h功能添加区

/**
 * @brief           链表头部插入
 * @param           头信息结构体的指针
 * @param           插入节点数据
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_prepend(udlist_t *ud, void *data);

.c功能添加区

/**
 * @brief           链表头部插入
 * @param           头信息结构体的指针
 * @param           插入节点数据
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_prepend(udlist_t *ud, void *data)
{
    udlist_append(ud, data);

    ud->fstnode_p = ud->fstnode_p->prev;

    return 0;
}

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

3 链表尾部插入 - Optional/Dependent

.h功能添加区

/**
 * @brief           链表尾部插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_append(udlist_t *ud, void *data);

.c功能添加区

/**
 * @brief           链表尾部插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_append(udlist_t *ud, void *data)
{
    node_t *temp1 = NULL;
    node_t *temp2 = NULL;

    /* 参数检查 */
    if (NULL == ud || NULL == data)
    {
    #ifdef DEBUG
        printf("udlist_append: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == data) */

    /* 1.创建一个新的节点 */
    temp1 = __node_calloc(ud);

    /* 2.节点数据输入 */
    temp1->next = temp1;
    temp1->prev = temp1;
    memcpy(temp1->data, data, ud->size);

    /* 3.数据尾部插入 */
    if (0 == ud->count)
    {
        ud->fstnode_p = temp1;
    }
    else 
    {
        temp2 = ud->fstnode_p->prev;
        ud->fstnode_p->prev = temp1;
        temp2->next = temp1;
        temp1->prev = temp2;
        temp1->next = ud->fstnode_p;
    }


    /* 4.刷新信息 */
    ud->count++;

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;     
}

4 链表的遍历 - Optional

.h功能添加区

/**
 * @brief           链表的遍历
 * @param           头信息结构体的指针
 * @param           自定义打印数据函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_traverse(udlist_t *ud, op_t my_print);

.c功能添加区

/**
 * @brief           链表的遍历
 * @param           头信息结构体的指针
 * @param           自定义打印数据函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_traverse(udlist_t *ud, op_t my_print)
{
    node_t *temp = NULL;

    /* 参数检查 */
    if (NULL == ud || NULL == my_print)
    {
    #ifdef DEBUG
        printf("udlist_traverse: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == my_print) */



    /* 链表的遍历 */
    temp = ud->fstnode_p;
    do 
    {
        my_print(temp->data);
        temp = temp->next;
    }
    while (temp != ud->fstnode_p);



    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;   
}

5 链表的反向遍历 - Optional

.h功能添加区

/**
 * @brief           链表的反向遍历
 * @param           头信息结构体的指针
 * @param           自定义打印数据函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_traverse_back(udlist_t *ud, op_t my_print);

.c功能添加区

/**
 * @brief           链表的反向遍历
 * @param           头信息结构体的指针
 * @param           自定义打印数据函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_traverse_back(udlist_t *ud, op_t my_print)
{
    node_t *temp = NULL;

    /* 参数检查 */
    if (NULL == ud || NULL == my_print)
    {
    #ifdef DEBUG
        printf("udlist_traverse_back: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == my_print) */



    /* 链表的遍历 */
    temp = ud->fstnode_p;
    do 
    {
        my_print(temp->data);
        temp = temp->prev;
    }
    while (temp != ud->fstnode_p);



    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;   
}

6 链表的销毁 - Necessary

.h功能添加区

/**
 * @brief           链表销毁函数(不包括头信息结构体)
 * @param           头信息结构体的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_destroy(udlist_t *ud);

.c功能添加区

/**
 * @brief           链表销毁函数(不包括头信息结构体)
 * @param           头信息结构体的指针
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_destroy(udlist_t *ud)
{
    node_t *temp = NULL;
    node_t *save = NULL;

    /* 参数检查 */
    if (NULL == ud)
    {
    #ifdef DEBUG
        printf("udlist_destroy: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud) */    

    temp = ud->fstnode_p;

    /* 依次释放节点空间 */
    if (NULL != temp)
    {
        do 
        {
            /* 1.保存下个节点的指针 */
            save = temp->next;

            /* 2.释放数据空间 */
            ud->my_destroy(temp->data);
            temp->data = NULL;

            /* 3.释放节点空间 */
            free(temp);
            temp = NULL;

            /* 4.指向下一个节点 */
            temp = save;
        }
        while (temp != ud->fstnode_p);
    } /* end of if (NULL != temp) */

    /* 头信息刷新 */
    ud->fstnode_p = NULL;
    ud->count = 0;

    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;   
}

7 链表头信息结构体销毁 - Necessary

.h功能添加区

/**
 * @brief           头信息结构体销毁函数
 * @param           头信息结构体的指针的地址
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int head_destroy(udlist_t **p);

.c功能添加区

/**
 * @brief           头信息结构体销毁函数
 * @param           头信息结构体的指针的地址
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int head_destroy(udlist_t **p)
{
    /* 参数检查 */
    if (NULL == p)
    {
    #ifdef DEBUG
        printf("head_destroy: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == p) */  

    /* 销毁结构体空间 */
    free(*p);
    *p = NULL;

    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;  
}

8 获取链表中节点的个数 - Optional

.h功能添加区

/**
 * @brief           获取链表中节点的个数
 * @param           头信息结构体的指针
 * @return          链表节点个数
 */
int get_count(udlist_t *p);

.c功能添加区

/**
 * @brief           获取链表中节点的个数
 * @param           头信息结构体的指针
 * @return          链表节点个数
 */
int get_count(udlist_t *p)
{
    /* 参数检查 */
    if (NULL == p)
    {
    #ifdef DEBUG
        printf("get_count: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == p) */  

    return p->count;

ERR0:
    return PAR_ERROR;    
}

9 链表根据索引插入数据 - Optional

.h功能添加区

/**
 * @brief           链表根据索引插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @param           索引值
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_insert_by_index(udlist_t *ud, void *data, int index);

.c功能添加区

/**
 * @brief           链表根据索引插入
 * @param           头信息结构体的指针
 * @param           数据的指针
 * @param           索引值
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_insert_by_index(udlist_t *ud, void *data, int index)
{
    node_t *temp1 = NULL;
    node_t *temp2 = NULL;
    node_t *save = NULL;
    int i = 0;


    /* 参数检查 */
    if (NULL == ud || NULL == data || index < 0)
    {
    #ifdef DEBUG
        printf("udlist_insert_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("udlist_delete_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("udlist_modify_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("udlist_retrieve_by_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto 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 DEBUG
        printf("get_match_index: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */


    /* 判断是否为空链表 */
    if (NULL == ud->fstnode_p)
    {
        goto ERR1;
    } /* end of if (NULL == ud->fstnode_p) */

    /* 寻找匹配索引 */
    index = 0;
    temp = ud->fstnode_p;
    while (1)
    {
        if (MATCH_SUCCESS == op_cmp(temp->data, key))
        {
            return index;
        } /* end of if (MATCH_SUCCESS == op_cmp(temp->data, key)) */

        temp = temp->next;
        if (ud->fstnode_p == temp)
        {
            goto ERR1;
        } /* end of if (ud->fstnode_p == temp) */
        index++;
    } /* end of while (1) */


ERR0:
    return PAR_ERROR;
ERR1:
    return MATCH_FAIL; 
}

14 链表根据关键字删除数据 - Optional

.h功能添加区

/**
 * @brief           链表根据关键字删除
 * @param           头信息结构体的指针
 * @param           关键字
 * @param           自定义比较函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_delete_by_key(udlist_t *ud, void *key, cmp_t op_cmp);

.c功能添加区

/**
 * @brief           链表根据关键字删除
 * @param           头信息结构体的指针
 * @param           关键字
 * @param           自定义比较函数
 * @return          
 *      @arg  0:正常
 *      @arg  PAR_ERROR:参数错误
 *      @arg  FUN_ERROR:函数错误
 */
int udlist_delete_by_key(udlist_t *ud, void *key, cmp_t op_cmp)
{
    int index = 0;

    /* 参数检查 */
    if (NULL == ud || NULL == key || NULL == op_cmp)
    {
    #ifdef DEBUG
        printf("udlist_delete_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */


    /* 获取匹配索引 */
    index = get_match_index(ud, key, op_cmp);
    if (PAR_ERROR == index || MATCH_FAIL == index)
    {
        goto ERR1;
    } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


    /* 根据索引删除节点 */
    udlist_delete_by_index(ud, index);


    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;        
}

使用此功能同时需要添加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 DEBUG
        printf("udlist_modify_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) */


    /* 获取匹配索引 */
    index = get_match_index(ud, key, op_cmp);
    if (PAR_ERROR == index || MATCH_FAIL == index)
    {
        goto ERR1;
    } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


    /* 根据索引修改数据 */
    udlist_modify_by_index(ud, data, index);


    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR; 
}

使用此功能同时需要添加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 DEBUG
        printf("udlist_retrieve_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) */


    /* 获取匹配索引 */
    index = get_match_index(ud, key, op_cmp);
    if (PAR_ERROR == index || MATCH_FAIL == index)
    {
        goto ERR1;
    } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */

    /* 根据索引获取数据 */
    udlist_retrieve_by_index(ud, data, index);

    return 0;


ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR; 
}

使用此功能同时需要添加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 DEBUG
        printf("udlist_delete_all_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */

    while (1)
    {
        /* 获取匹配索引 */
        index = get_match_index(ud, key, op_cmp);
        if (PAR_ERROR == index || MATCH_FAIL == index)
        {
            goto ERR1;
        } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


        /* 根据索引删除节点 */
        udlist_delete_by_index(ud, index);

    } /* end of while (1) */

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR;  

}

使用此功能同时需要添加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 DEBUG
        printf("udlist_modify_all_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp || NULL == data) */

    while (1)
    {
        /* 获取匹配索引 */
        index = get_match_index(ud, key, op_cmp);
        if (PAR_ERROR == index || MATCH_FAIL == index)
        {
            goto ERR1;
        } /* end of if (PAR_ERROR == index || MATCH_FAIL == index) */


        /* 根据索引修改数据 */
        udlist_modify_by_index(ud, data, index);

    } /* end of while (1) */

    return 0;

ERR0:
    return PAR_ERROR;
ERR1:
    return FUN_ERROR; 
}

使用此功能同时需要添加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 DEBUG
        printf("udlist_find_all_index_by_key: Parameter error\n");
    #elif defined FILE_DEBUG
        
    #endif
        goto ERR0;        
    } /* end of if (NULL == ud || NULL == key || NULL == op_cmp) */


    /* 判断链表是否存在 */
    if (NULL == ud->fstnode_p)
    {
        goto ERR1;
    } /* end of if (NULL == ud->fstnode_p) */


    /* 创建存储索引的链表头信息结构体 */
    index_head = udlist_create(sizeof(int), index_destroy);


    /* 查找索引并插入链表 */
    temp = ud->fstnode_p;
    index = 0;
    do 
    {
        if (MATCH_SUCCESS == op_cmp(temp->data, key))
        {
            udlist_append(index_head, &index);
        } /* end of if (MATCH_SUCCESS == op_cmp(temp->data, key)) */

        index++;
        temp = temp->next;
    }
    while (temp != ud->fstnode_p);



    /* 判断是否为空链表 */
    if (0 == get_count(index_head))
    {
        head_destroy(&index_head);
    } /* end of if (0 == get_count(index_head)) */


    return index_head;


ERR0:
    return (void *)PAR_ERROR;
ERR1:
    return NULL;
}

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

测试代码添加模块

1 自定义数据销毁函数 - Necessary

int node_destroy(void *data){}

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.coloradmin.cn/o/1500688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试面试】银行项目测试面试题+答案(一)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 面试题&#xff1…

如何做代币分析:以 ARB 币为例

作者&#xff1a;lesleyfootprint.network 编译&#xff1a;mingfootprint.network 数据源&#xff1a;ARB 代币仪表板 &#xff08;仅包括以太坊数据&#xff09; 在加密货币和数字资产领域&#xff0c;代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关的数据…

Vue2里,利用原生js input的 type=“file“时,获取上传成功后的文件名及文件内容。下载文件到本地

功能场景:现在有个上传下载文件的功能,不需要调后端接口,因为需求是不需要将文件存到数据库里。如下图,是上传成功的场景: 这里限制上传accept类型为pem, 这里主要用到了input的change事件,如果没上传文件则提醒上传文件后再下载,下载功能主要是运用创建a元素,传入blo…

go语言-k8s宿主信息采集运维脚本

背景 由于工作需要&#xff0c;需要采集k8s集群中的宿主相关信息&#xff0c;包括cpu,memory,lvm,标签等信息。通常作为SRE会主选shell或python脚本来实现。但最近我们团队主流开发语言已经切换到golang.所以本次尝试用go语言来写写运维脚本。 实现流程图 代码实现 package m…

移掉 K 位数字(LeetCode 402)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路4.1 暴力法4.2 贪心 单调栈 参考文献 1.问题描述 给你一个以字符串表示的非负整数 num 和一个整数 k&#xff0c;移除这个数中的 k 位数字&#xff0c;使得剩下的整数最小。请你以字符串形式返回这个最小的整数。 示例 1 …

【产品测试】Bug报告的四个元素,你知道吗?

前言 由于任何由人编写的程序都不可避免的存在着不符合测试需求的错误&#xff0c;也就是bug。因此需要一个方法来跟踪、分析和展示那些测试活动&#xff0c;避免偏离最小。这种方法称之为错误跟踪系统。它主要是有效的管理缺陷&#xff0c;实现以下作用&#xff1a; 1)减少由…

YOLOX论文解读

paper&#xff1a;YOLOX: Exceeding YOLO Series in 2021 official implementation&#xff1a;https://github.com/Megvii-BaseDetection/YOLOX 本文的创新点 本文在YOLOv3的基础上进行了一些改进&#xff1a;包括将检测头进行解耦的decoupled head、从anchor-based转为anc…

经典定时任务结构设计:时间轮(Timing Wheel)案例和实现原理

1、直接上案例 import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; import io.netty.util.TimerTask; import lombok.extern.log4j.Log4j2;import java.util.concurrent.TimeUnit;/*** ClassName Test* Author will* Date 2024/3/8 16:31* Version 1.0.1*…

【PCIe】TLP结构与配置空间

&#x1f525;博客主页&#xff1a;PannLZ 文章目录 PCIe TLP结构PCIe配置空间和地址空间 PCIe TLP结构 TLP 主要由3个部分组成&#xff1a; Header 、 数据(可选&#xff0c;取决于具体的TLP 类 型 ) 和 ECRC (End to End CRC, 可选)。TLP 都始于发送端的事务层&#xff0c;终…

网络仿真(二)

时延和丢包率 网络中的节点之间时延&#xff08;延迟&#xff09;和丢包率是衡量网络性能的两个关键指标。 时延&#xff08;延迟&#xff09;&#xff1a;时延是指数据在网络中从一个节点传输到另一个节点所需的时间。这包括处理时延&#xff08;数据在节点处理的时间&#x…

ENVI必须会教程—Sentinel-2数据的读取与波段组合加载

实验2&#xff1a;读取Sentinel-2影像 目的&#xff1a;了解Sentinel-2影像读取方法&#xff0c;熟悉各波段及组合 过程&#xff1a; ①读取数据&#xff1a;在标题栏选择“文件”选项&#xff0c;点击“打开为”&#xff0c;选择“光学传感器”&#xff0c;由于哨兵2号数据…

Java后端八股笔记

Java后端八股笔记 Redis八股 上两种都有可能导致脏数据 所以使用两次删除缓存的技术&#xff0c;延时是因为数据库有主从问题需要更新&#xff0c;无法达到完全的强一致性&#xff0c;只能达到控制一致性。 一般放入缓存中的数据都是读多写少的数据 业务逻辑代码&#x1f44…

#stm32外设总结电容触摸按键

BS8116A-3 IRQ 外部中断请求 NMOS输出内部上拉 SCL SDA IIC通信接口 VDD 供电电压2.2-5.5V Ct电容: 0~25 pF 电容越大灵敏度越低 1、 软件使用流程 初始化 将IIC的两个引脚初始化为复用开漏模式 按键引脚设置上拉输入 下降沿触发外部中断 void KEY_Init(void) {//uint8_t …

音视频学习笔记——实现PCM和H264合成MP4功能

本文主要记录实现PCM和H264合成MP4功能的整个框架&#xff0c;各个模块中FFmpeg的api使用流程&#xff0c;便于后续学习和复盘。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习&#xff0c;梳理总结后写下文章&#xff0c;对音视频相关内容感兴趣…

2024最新算法:冠豪猪优化算法(Crested Porcupine Optimizer,CPO)求解23个基准函数(提供MATLAB代码)

一、冠豪猪优化算法 冠豪猪优化算法(Crested Porcupine Optimizer&#xff0c;CPO)由Mohamed Abdel-Basset等人于2024年提出&#xff0c;该算法模拟冠豪猪的四种不同保护机制&#xff1a;视觉、听觉、气味和物理攻击。第一和第二防御技术&#xff08;视觉和听觉&#xff09;反…

安装nexus + 部署私有maven仓库

安装nexus 部署私有maven仓库 文章目录 安装nexus 部署私有maven仓库1.下载2.解压3.修改配置文件4.启动5.访问6.查看默认密码7.创建私库8.修改代码配置文件9.在maven 的setting.xml中配置私库的账号密码10.运行manve 【deploy】命令测试11.maven项目引用私库12. 重新加载mave…

C/C++内存管理【C++】

目录 一、 C/C内存分布1. C内存管理方式(1) new和delete操作内置类型(2) new和delete操作自定义类型 二、 operator new与operator delete函数三、 malloc/free和new/delete的区别四、内存泄漏 一、 C/C内存分布 C/C程序的内存布局会因编译器和操作系统而有所不同&#xff0c;但…

红帆ioffice-udfGetDocStep.asmx存在SQL注入漏洞

产品简介 红帆iOffice.net从最早满足医院行政办公需求&#xff08;传统OA&#xff09;&#xff0c;到目前融合了卫生主管部门的管理规范和众多行业特色应用&#xff0c;是目前唯一定位于解决医院综合业务管理的软件&#xff0c;是最符合医院行业特点的医院综合业务管理平台&am…

上门服务小程序|上门服务系统成品功能包含哪些?

随着移动互联网的快速发展&#xff0c;上门服务小程序成为了一种创新的家政服务模式。它不仅为用户带来了极大的便利&#xff0c;还能在提高服务效率和质量方面发挥作用。通过上门服务小程序&#xff0c;用户可以轻松预约按摩或理疗服务&#xff0c;无需繁琐操作&#xff0c;只…

9、JavaWeb-文件上传-配置文件

P146 案例-文件上传-简介 文件上传&#xff0c;将本地图片、视频等文件上传到服务器&#xff0c;供其他用户浏览下载的过程。 文件上传前端页面三要素&#xff1a; 如果前端表单的编码格式选择的默认编码方式x-www.form-urlencoded&#xff0c;则提交的文件仅仅是文件名&…