当前位置: 首页 > news >正文

高效解耦:自定义内核链表实现指南(简化版)

文件结构

文件结构如下:

- kernelList.h // 通用链表节点定义及核心操作(不含Data)
- kernelList.c // 通用链表操作实现(不含Data依赖)
- data.h // Data结构定义及相关操作声明
- data.c // Data结构相关操作实现
- main.c // 测试代码(调用拆分后的接口)

具体实现

1. kernelList.h(通用链表模块,移除 Data 依赖)

仅保留链表节点( ListNode )及通用操作,不涉及 Data 结构:

#ifndef KERNELLIST_H
#define KERNELLIST_H
#include <stdio.h>
#include <stdlib.h>
// 通用链表节点(仅含前驱和后继指针,与用户数据解耦)
typedef struct list_node 
{struct list_node *prev; // 前驱指针struct list_node *next; // 后继指针
} ListNode;
// 初始化链表节点(前后指针指向自身)
static inline void list_init(ListNode *n) 
{n->prev = n;n->next = n;
}
// 头插法:在head后插入新节点
static inline void list_add_head(ListNode *head, ListNode *new_node) 
{new_node->next = head->next;new_node->prev = head;head->next->prev = new_node;head->next = new_node;
}
// 尾插法:在head前插入新节点(尾部)
static inline void list_add_tail(ListNode *head, ListNode *new_node) 
{new_node->prev = head->prev;new_node->next = head;head->prev->next = new_node;head->prev = new_node;
}
// 从链表中删除节点
static inline void list_del(ListNode *n) 
{n->prev->next = n->next;n->next->prev = n->prev;
}
#endif

2. kernelList.c(通用链表操作实现,无 Data 依赖)

        仅实现 kernelList.h 中声明的通用操作(本示例中均为 static inline 函数,无需额外实现,故文件可空或仅保留说明):

#include "kernelList.h"

3. data.hData 结构定义及相关操作)

独立定义 Data 结构(嵌入 ListNode ),并声明 Data 相关操作:

#ifndef DATA_H
#define DATA_H
#include "kernelList.h"
#include <stddef.h> // 用于offsetof
// 用户数据结构(嵌入链表节点)
typedef struct 
{int data; // 实际存储的数据ListNode node; // 嵌入通用链表节点
} Data;
// 从链表节点反向获取Data(核心:通过节点找数据)
#define get_data(n) (Data*)((char*)(n) - offsetof(Data, node))
// 创建Data节点(分配内存并初始化)
Data* create_data(int value);
// 遍历并打印Data链表
void data_show(ListNode *head);
// 根据数据值查找Data节点
Data* data_find(ListNode *head, int value);
// 销毁Data链表(释放所有节点)
void data_destroy(ListNode *head);
#endif

4. data.cData 相关操作实现)

实现 data.h 中声明的操作,依赖通用链表接口但不侵入链表模块:

#include "data.h"
// 创建Data节点(初始化数据和链表节点)
Data* create_data(int value) 
{Data *d = (Data*)malloc(sizeof(Data));if (!d) return NULL;d->data = value;list_init(&d->node); // 调用通用链表初始化return d;
}
// 遍历并打印Data链表
void data_show(ListNode *head) 
{ListNode *p = head->next; // 从head下一个节点开始printf("链表数据:");while (p != head) { // 回到head时结束Data *d = get_data(p); // 通过节点获取Dataprintf("%d ", d->data);p = p->next;}printf("\n");
}
// 根据数据值查找Data节点
Data* data_find(ListNode *head, int value) 
{ListNode *p = head->next;while (p != head) {Data *d = get_data(p);if (d->data == value) {return d; // 找到返回Data}p = p->next;}return NULL; // 未找到
}
// 销毁Data链表(释放所有节点)
void data_destroy(ListNode *head) 
{ListNode *p = head->next;while (p != head) {ListNode *temp = p;p = p->next;free(get_data(temp)); // 释放Data节点}list_init(head); // 重置头节点
}

5. main.c(测试代码,调用拆分后接口)

调整为使用 data.h 和通用链表接口:

#include "data.h" // 包含Data相关接口
#include "kernelList.h" // 包含通用链表接口
int main(int argc, char *argv[]) 
{// 定义头节点(哨兵,不存数据)ListNode head;list_init(&head); // 调用通用链表初始化// 1. 插入数据Data *d1 = create_data(111);list_add_tail(&head, &d1->node); // 尾插(通用接口)Data *d2 = create_data(222);list_add_head(&head, &d2->node); // 头插(通用接口)Data *d3 = create_data(333);list_add_head(&head, &d3->node); // 头插(通用接口)// 2. 打印链表(Data专属操作)data_show(&head); // 输出:333 222 111// 3. 查找数据(Data专属操作)Data *found = data_find(&head, 222);if (found) printf("找到数据:%d\n", found->data); // 输出:找到数据:222// 4. 删除数据if (found) {list_del(&found->node); // 通用删除接口free(found); // 释放Data}data_show(&head); // 输出:333 111// 5. 销毁链表(Data专属操作)data_destroy(&head);return 0;
}

核心思路

        1. 解耦通用链表与用户数据kernelList 模块仅负责 ListNode 的初始化、增删等通用操作,不依赖任何用户数据类型(如 Data ),可复用为其他数据类型的链表基础。

        2. Data 独立管理Data 作为用户数据类型,单独定义在 data.h / data.c 中,通过get_data 宏关联 ListNode ,实现节点数据的反向查找,且所有 Data 相关操作(创建、打印、查找、销毁)均在独立文件中实现。

        3. 接口清晰:通用操作( list_init / list_add 等)与用户数据操作( data_show / data_find 等)分离,降低模块间耦合度。

        拆分后,若需新增其他用户数据类型(如 Student Product ),只需复用 kernelList 模块,新增对应的数据文件(如 student.h / student.c )即可,无需修改链表核心代码。

http://www.lryc.cn/news/618623.html

相关文章:

  • Java进阶学习之不可变集合
  • 数据分析学习总结之实例练习(双十一淘宝美妆)
  • 非凸科技受邀参加Community Over Code Asia 2025 Rust分论坛
  • C#教程之NPOI读写excel文件XLS,XLSX格式
  • FPGA自学——FIFO缓存器
  • VisionPro——1.VP与C#联合
  • 初识数据结构——优先级队列(堆!堆!堆!)
  • 模板打印技术——Office XLS 打印模板:为政务土地确权定制的纸张替换利器—仙盟创梦IDE
  • LE AUDIO---Volume Control Service
  • Kimi K2 架构深度解析:万亿MoE模型的效率革命与智能体突破
  • 用STM32单片机控制支持正反转的电调
  • 1、JVM内存模型剖析及优化
  • Altium Designer 22使用笔记(6)---板框导入、自绘板框、原点设置
  • 荣耀手机无法连接win11电脑,错误消息:“无法在此设备上加载驱动程序 (hn_usbccgpfilter.sys)。”解决方案
  • 【Linux】Ext系列文件系统
  • 数据结构:后缀表达式:结合性 (Associativity) 与一元运算符 (Unary Operators)
  • 现代化水库运行管理矩阵建设的要点
  • AI Agent——基于 LangGraph 的多智能体任务路由与执行系统实战
  • 【实时Linux实战系列】实时能耗监测与优化技术
  • 《吃透 C++ 类和对象(上):封装、实例化与 this 指针详解》
  • Python训练营打卡Day30-文件的规范拆分和写法
  • 543.二叉树的直径
  • 【前端:Html】--2.进阶:表单
  • 数字孪生重构园区管理效率:技术落地与产业升级的三重跃迁
  • JVM学习笔记-----图解方法执行流程
  • Nginx 启用 HTTPS:阿里云免费 SSL 证书详细图文教程(新手0.5小时可完成)
  • openssl中,公钥和私钥的区别和作用?
  • API 接口接入开发全演示:淘宝商品数据实时抓取
  • 代码随想录刷题Day29
  • 基于51单片机220V交流电流检测系统过流阈值报警设计