🔣 DList_M - 双向链表(多种数据类型)

可存储任意类型数据的双向链表,每个数据自带操作函数

📖 概述

DList_M (Double List Multiple Data) 是一种双向链表数据结构,可以存储任意类型的数据。与 DList_S 不同,DList_M 不需要预先提供统一的操作集,每个 Data_M 数据都自带 InfoOfData 指针来描述自己的操作方式。

⚙️ 数据类型定义

// 链表节点
typedef struct Node_M_inDList {
    struct Node_M_inDList* prev;  // 前驱节点
    struct Node_M_inDList* next;   // 后继节点
    Data_M val;                    // 数据(自带操作集)
} Node_M_inDList;

// DList_M 链表
typedef struct {
    Node_M_inDList* head;      // 头节点
    Node_M_inDList* tail;      // 尾节点
    int size;                  // 链表长度
} DList_M;

🚀 快速开始

#include "base.h"
#include "List/DList/Multiple_Data/dlist_mdata.h"
#include "Oper/Int_Info/int_info.h"
#include "Oper/String_Info/string_info.h"

int main() {
    // 1. 初始化链表
    DList_M list;
    initMDList(&list);

    // 2. 插入不同类型的数据
    // 插入整数
    int num = 42;
    Data_M data1 = Data_M_OWN(&num, NULL, &Info_Int, 0);
    insertMDataAtEndInMDList(&list, data1);

    // 插入字符串
    char str[] = "Hello";
    Data_M data2 = Data_M_OWN(str, NULL, &Info_String, 0);
    insertMDataAtEndInMDList(&list, data2);

    // 3. 打印链表
    printMDList(&list);

    // 4. 释放链表
    freeMDList(&list);
    return 0;
}

📋 函数列表

🔧 初始化与销毁

void initMDList(DList_M* plist)

初始化 DList_M

参数:
  • plist - DList_M 类型的指针
void freeMDataInMDList(Data_M* inputData)

释放 MData (Data_M 类型) 的内容

参数:
  • inputData - MData 类型指针 (Data_M 类型)
void freeMDList(DList_M* plist)

清除 DList_M 链表

参数:
  • plist - DList_M 链表指针

➕ 插入操作

InfoOfReturn insertMDataAtEndInMDList(DList_M* plist, Data_M inputData)

在 DList_M 链表的尾部插入节点

参数:
  • plist - DList_M 链表指针
  • inputData - Data_M 类型数据
返回: 返回 InfoOfReturn 中的枚举类型
InfoOfReturn insertMDataAtStartInMDList(DList_M* plist, Data_M inputData)

在 DList_M 链表的头部插入节点

参数:
  • plist - DList_M 链表指针
  • inputData - Data_M 类型数据
返回: 返回 InfoOfReturn 中的枚举类型
InfoOfReturn insertMDataAtPosInMDList(DList_M* plist, Data_M inputData, int pos)

在 DList_M 链表指定位置插入数据

参数:
  • plist - DList_M 链表指针
  • inputData - Data_M 类型数据
  • pos - 位置的范围在 [0, DList_M.size],范围的两端分别代表头插和尾插
返回: 返回 InfoOfReturn 中的枚举类型

➖ 删除操作

InfoOfReturn delStartNodeInMDList(DList_M* plist)

删除 DList_M 链表头节点

参数:
  • plist - DList_M 链表指针
返回: 返回 InfoOfReturn 中的枚举类型
InfoOfReturn delEndNodeInMDList(DList_M* plist)

删除 DList_M 链表尾节点

参数:
  • plist - DList_M 链表指针
返回: 返回 InfoOfReturn 中的枚举类型
InfoOfReturn delNodeByMDataInMDList(DList_M* plist, Data_M inputData)

通过 MData (Data_M 类型) 数据来删除 DList_M 中的节点

参数:
  • plist - DList_M 链表指针
  • inputData - Data_M 类型数据
返回: 返回 InfoOfReturn 中的枚举类型
InfoOfReturn delNodeByPosInMDList(DList_M* plist, int pos)

通过位置删除 DList_M 的节点

参数:
  • plist - DList_M 链表指针
  • pos - 要删除的位置(从 0 开始)
返回: 返回 InfoOfReturn 中的枚举类型

🔍 查询操作

Data_M getPtrMDataByPosInMDList(DList_M* plist, int pos)

通过位置 Pos 返回 MData 的指针 (Data_M 类型),可直接修改内部的 void* data 和 void* content 内容

参数:
  • plist - DList_M 类型指针
  • pos - 位置(从 0 开始)
返回: 返回 Data_M 类型数据,若没有返回空 Data_M 类型数据,通过 Data.isEmpty 进行查看
警告: 返回的指针直接指向链表内部数据,请勿 free
Data_M getCopyMDataByPosInMDList(DList_M* plist, int pos)

通过 Pos 位置返回 MData (Data_M 类型),注意这里 MData 中的 void* data 和 void* content 都是复制的,使用完后记得释放

参数:
  • plist - DList_M 类型指针
  • pos - 位置(从 0 开始)
返回: 返回 Data_M 类型数据,若没有返回空 Data_M 类型数据,通过 Data.isEmpty 进行查看
警告: 返回的是复制的数据,使用后需调用 freeMDataInMDList 释放
Data_M getPtrMDataByMDataInMDList(DList_M* plist, Data_M inputData)

通过 MData (Data_M 类型) 返回 MData 的指针 (Data_M 类型),可直接修改内部的 void* data 和 void* content 内容

参数:
  • plist - DList_M 类型指针
  • inputData - 输入的 MData 类型 (Data_M 类型)
返回: 返回 Data_M 类型数据,若没有返回空 Data_M 类型数据,通过 Data.isEmpty 进行查看
bool hasMDataInMDList(DList_M* plist, Data_M inputData)

判断 Data_M 数据是否在 DList_M 里面

参数:
  • plist - DList_M 类型指针
  • inputData - Data_M 类型数据
返回: 有就返回 true,没有就 false

🔄 其他操作

void reverseMDList(DList_M* plist)

反转 DList_M 链表

参数:
  • plist - DList_M 链表指针
void printSDataInMDList(Data_M inputData)

打印 DList_M 链表中的 Data_M 数据

参数:
  • inputData - Data_M 类型数据
void printMDList(DList_M* plist)

打印 DList_M 链表数据

参数:
  • plist - DList_M 链表指针

💡 完整示例

#include <stdio.h>
#include 
#include "base.h"
#include "List/DList/Multiple_Data/dlist_mdata.h"
#include "Oper/Int_Info/int_info.h"
#include "Oper/Double_Info/double_info.h"

int main() {
    // 初始化链表
    DList_M list;
    initMDList(&list);

    // 插入不同类型的数据
    int num1 = 100, num2 = 200;
    double val = 3.14;

    // 插入整数
    Data_M data1 = Data_M_OWN(&num1, NULL, &Info_Int, 0);
    insertMDataAtEndInMDList(&list, data1);

    // 插入整数
    Data_M data2 = Data_M_OWN(&num2, NULL, &Info_Int, 0);
    insertMDataAtStartInMDList(&list, data2);

    // 插入浮点数
    Data_M data3 = Data_M_OWN(&val, NULL, &Info_Double, 0);
    insertMDataAtPosInMDList(&list, data3, 1);

    printf("=== 链表内容 ===\n");
    printMDList(&list);

    // 反转链表
    printf("\n=== 反转后 ===\n");
    reverseMDList(&list);
    printMDList(&list);

    // 释放链表
    freeMDList(&list);
    return 0;
}

🔄 DList_S vs DList_M

特性 DList_S DList_M
数据类型 只能存储单一类型 可存储任意类型
初始化 需要传入 InfoOfData 不需要,链表自管理
灵活性 较低
内存开销 较低(共享操作集) 较高(每个节点自带操作集)
适用场景 同类数据集合 异构数据、JSON-like 数据

⚠️ 注意事项