企业级链表介绍

如果我们使用原始的C语言写链表的话,数据类型是被固定死的,如果业务换了 需要另一种数据类型,我们又得重新在写一个链表,当然我们可以使用void* 万能指针,因为void* 可以接受任意类型的指针,那么我们就可以接受任意类型的数据的地址了,我们只需要维护用户提供的数据地址就可以。详细介绍请看:数据结构与算法:单链表(利用万能指针实现对任意类型数据进行操作)。今天我们介绍另外一种方法,让我们的写的链表不受业务结构而限制,在我们用的数据类型发生改变时并不需要去改变底层的链表结构。这就今天要和大家分享的企业级链表,感觉这种思想太赞了。我们在c语言中一般使用结构体作为复合数据类型,可以定义我们需要的数据集。如果我们将具体的业务数据放到LinkNode 链表结点中去,就会遇到前面分析的问题,业务和底层代码实现 耦合的太紧了。企业级链表就是来解决这个问题。

企业级链表分析

接前面分析的问题,那么为何不把业务数据域分离出来呢?链表结点LinkNode中只放next指针域

typedef struct LinkNode
{
struct LinkNode* next;
}LinkNode;

那我们的数据业务数据呢?放哪里呀?下面就是企业级链表的高明处。你定义的业务数据,该怎么定义就怎么定义,只需将LinkNode 作为你定义的业务数据类型的第一个成员 就行了。比如说,下面定义一个学生数据类型。由于LinkNode 放在我们自定义的数据类型Student类型的第一个成员,那么&LinkNode和&Student 他们是一样的!他们的起始地址是重合的。那么我们底层使用LinkNode数据类型,就不用管用户上层怎么定义了,你只要放置一个LinkNode成员在你定义的数据 类型的第一位,你将Student数据的地址传进来,我们依旧可以取到LinkNode数据,就行使用LinkNode 来维护链表之间的前驱后继关系就如同下图一样,给你定义的数据类型 安装一个钩子,将你定义的数据像链表一样链接起来了。

typedef struct Student
{
LinkNode node;
char name[64];
int age;
}Student;

企业级链表代码实现

相关算法还是和正常的单链表差不多,只是用户使用的时候,按照要求使用就ok,LinkNode做为用户定义的业务数据的第一个成员,然后可以使用了。

CompanyLinkList.h

#pragma once
#ifndef __COMPANY_LINKLIST_H__
#define __COMPANY_LINKLIST_H__typedef enum {TRUE,FASLE} BOOLEAN  ;//成功状态 FALSE 不成功 TRUE成功
typedef enum { ERROR, OK } STATUS;  //状态信息 ERROR 发生错误 OK 一切正常typedef struct LinkNode
{struct LinkNode* next;
}LinkNode;typedef struct LinkList
{LinkNode head;int size;
}LinkList;//创建链表并初始化
LinkList* Create_LinkList();//插入数据 根据位置插入
int Insert_LinkList(LinkList* list,int pos, LinkNode* data);//删除数据 根据位置删除
int Remove_LinkList(LinkList* list, int pos);//查找数据,根据数据内容
int Find_LinkList(LinkList* list, LinkNode* data,int (*Compare_Function)(LinkNode*,LinkNode*));//遍历链表
int Foreach_LinkList(LinkList* list, void(*Foreach_Function)(LinkNode*));//清空数据 链表仍然可用
int Clear_LinkList(LinkList* list);//销毁链表 链表不可用
int Destroy_LinkList(LinkList* list);#endif // !__COMPANY_LINKLIST_H__

CompanyLinkList.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CompanyLinkList.h"//创建链表并初始化
LinkList* Create_LinkList()
{LinkList* list = (LinkList*)malloc(sizeof(LinkList));list->size = 0;list->head.next = NULL;return list;
}//插入结点数据的地址 根据位置插入,pos从1开始
int Insert_LinkList(LinkList* list, int pos, LinkNode* data)
{if (NULL == list || NULL==data){return ERROR;}//位置太小插入到 第一个位置if (pos < 1){pos = 1;}//位置太大插入到 尾部if (pos > list->size){pos = list->size + 1;}//找到插入位置的前驱结点LinkNode* pre = &list->head;for (int i = 1; i < pos; i++){pre = pre->next;}data->next = pre->next;pre->next = data;list->size++;return OK;
}//删除数据 根据位置删除 pos 从1 开始
int Remove_LinkList(LinkList* list, int pos)
{//list为NULL 或者位置非法 直接返回if (NULL == list || pos < 1 || pos > list->size){return ERROR;}LinkNode* pre = &list->head;//同样找到删除结点的前驱for (int i = 1; i < pos; i++){pre = pre->next;}//将不要的元素略过,因为我们只维护用户提供的数据的地址,释放内存不归我们管pre->next = pre->next->next;list->size--;return OK;
}//查找数据,根据数据内容,返回时链表中的第几个元素,从1开始计数 ,没找到返回-1
//Compare_Function 用户提供 结点元素比较的回调函数
int Find_LinkList(LinkList* list, LinkNode* data, int(*Compare_Function)(LinkNode*, LinkNode*))
{if (NULL == list || NULL == data || NULL == Compare_Function){return ERROR;}LinkNode* node = list->head.next;int flag = 0;// 是否查找到的标志int index = 1;while (node!=NULL){if (Compare_Function(node, data)){flag = 1;break;}node = node->next;index++;}return flag ? index : -1;
}//遍历链表
//Foreach_Function 用户提供的遍历链表元素的回调函数
int Foreach_LinkList(LinkList* list, void(*Foreach_Function)(LinkNode*))
{if (NULL == list || NULL == Foreach_Function){return ERROR;}LinkNode* node = list->head.next;while (NULL!=node){Foreach_Function(node);node = node->next;}return OK;
}//清空数据 链表仍然可用
int Clear_LinkList(LinkList* list)
{if (NULL == list){return ERROR;}list->size = 0;list->head.next = NULL;return OK;
}//销毁链表 链表不可用
int Destroy_LinkList(LinkList* list)
{if (NULL == list){return ERROR;}free(list);list = NULL;return OK;
}//用户使用 企业级链表,只需要在自己定义的类型中将LinkNode 作为第一个成员即可使用
//这样就将 具体的业务和底层链表算法 进行分离了
typedef struct Student
{LinkNode node;char name[64];int age;
}Student;
//用户定义遍历的回调函数
void Print_Student(LinkNode* node)
{Student* stu = (Student*)node;printf("姓名:%s,年龄%d\n",stu->name,stu->age);return;
}
//用户定义结点的比较回调函数
int Compare_Student(LinkNode* node1, LinkNode* node2)
{Student* stu1 = (Student*)node1;Student* stu2 = (Student*)node2;//年龄和名字相同才相同if (stu1->age == stu2->age && 0 == strcmp(stu1->name, stu2->name)){return 1;}return 0;
}int main(int argc, char *argv[])
{//企业链表使用Student s1, s2, s3, s4, s5;s1.age = 11;s2.age = 12;s3.age = 13;s4.age = 14;s5.age = 15;strcpy(s1.name, "aaa");strcpy(s2.name, "bbb");strcpy(s3.name, "ccc");strcpy(s4.name, "ddd");strcpy(s5.name, "eee");//创建链表LinkList* list = Create_LinkList();//插入Insert_LinkList(list, 1, (LinkNode*)&s1);Insert_LinkList(list, 2, (LinkNode*)&s2);Insert_LinkList(list, 3, (LinkNode*)&s3);Insert_LinkList(list, 4, (LinkNode*)&s4);Insert_LinkList(list, 5, (LinkNode*)&s5);printf("插入5条数据后遍历:\n");Foreach_LinkList(list, Print_Student);//查找Student s6;s6.age = 15;strcpy(s6.name, "eee");int index = Find_LinkList(list,(LinkNode*)&s6, Compare_Student);printf("查找的元素name=eee,age=15,是链表中第%d个元素\n",index);//删除元素Remove_LinkList(list, 1);printf("删除第1个结点后遍历:\n");Foreach_LinkList(list, Print_Student);return 0;
}

企业级链表运行验证

数据结构与算法:企业级链表实现(超详细)相关推荐

  1. 数据结构与算法之线性表(超详细顺序表、链表)

    原创公众号:bigsai 文章已收录在 全网都在关注的数据结构与算法学习仓库 欢迎star 前言 通过前面数据结构与算法基础知识我么知道了数据结构的一些概念和重要性,那么我们今天总结下线性表相关的内容 ...

  2. 拿命 3 天肝出来的计算机考研数据结构与算法复习笔记(超详细教程,更新中)

    数据结构与算法 基本概述 数据结构指的是"一组数据的存储结构",算法指的是"操作数据的一组方法". 数据结构是为算法服务的,算法是要作用再特定的数据结构上的. ...

  3. python定义链表节点_Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】...

    本文实例讲述了Python数据结构与算法之链表定义与用法.分享给大家供大家参考,具体如下: 本文将为大家讲解: (1)从链表节点的定义开始,以类的方式,面向对象的思想进行链表的设计 (2)链表类插入和 ...

  4. 数据结构与算法之链表结构寻找p、q最近的公共祖先

    链表结构,寻找p.q最近的公共祖先 数据结构与算法之链表结构寻找p.q最近的公共祖先 链表结构,寻找p.q最近的公共祖先 问题 想法 代码 问题 设一棵二叉树的结点结构为(LLINK, INFO, R ...

  5. 数据结构与算法--单链表相关面试题

    此文章仅作为自己学习过程中的记录和总结,同时会有意地去用英文来做笔记,一些术语的英译不太准确,内容如有错漏也请多指教,谢谢! 一.概述 获取单链表的有效元素个数[新浪面试题1] 获取单链表倒数第k个结 ...

  6. 数据结构与算法 内核链表实现商品购物系统项目+Makefile

    数据结构与算法 内核链表实现商品购物系统项目 第一章 项目实现思维 [1]编译介绍 [2]框架思维 第二章 Makefile编写 第三章 代码编写实现 [1]favorite.txt文件 [2]his ...

  7. 一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题

    文章目录 1 链表 1.1 常见题型及解题策略 1.1.1 LeetCode中关于链表的题目有以下五种类型题: 1.1.2 解题策略 1.2 链表的基本内容 1.2.1 链表的基本结构: 1.2.2 ...

  8. java数据接口之链表_Java数据结构和算法之链表

    三.链表 链结点 在链表中,每个数据项都被包含在'点"中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LI ...

  9. 数据结构与算法--复杂链表的复制

    复杂链表的复制 题目:实现一个函数complexListNode 复制一个复杂链表.在链表中,每个节点除了有一个next指针指向下一个节点,还有另外一个before节点,before节点指向链表中任意 ...

  10. Java数据结构和算法(四)--链表

    日常开发中,数组和集合使用的很多,而数组的无序插入和删除效率都是偏低的,这点在学习ArrayList源码的时候就知道了,因为需要把要 插入索引后面的所以元素全部后移一位. 而本文会详细讲解链表,可以解 ...

最新文章

  1. 导入表编程-枚举导入表
  2. python爬虫自学笔记分析解密_python爬虫学习笔记——1 各种文本分析工具简介之汇总...
  3. ICLR 2020 开源论文 | 隐空间的图神经网络:Geom-GCN
  4. 信息学奥赛一本通 1193:吃糖果 | OpenJudge NOI 2.6 1944:吃糖果
  5. 谷歌上线数据搜索引擎 Dataset Search
  6. c#使用zlib.net压缩解压byte数组
  7. 解决方法 svn checkout 更改用户名密码/断网续传
  8. persistence java_Java数据持久层 - Persistence Manager Factory
  9. js打开本地文件_JS逆向|高频问题:为何Reres插件总是替换本地文件失败?
  10. C++打印size_t和ssize_t和int64_t和uint64_t
  11. windows 系统配置多网关win添加静态路由
  12. linux下通过phpize为php在不重新编译php情况下安装模块memcache
  13. linux 脚本 格式化,Shell脚本批量格式化文件名
  14. 绿联蓝牙驱动 linux,Ugreen绿联蓝牙驱动下载
  15. Python轮盘抽奖游戏
  16. hdu4699(对顶栈模拟+简单dp)
  17. C#调用百度大脑API初探2
  18. IJCAI 2022 | 即插即用分类器模块:一行代码大幅提升零样本学习方法效果
  19. C#编写的winform程序绑定comboBox成功,添加一个默认的文字选项请选择
  20. 山姆公司关于营销培训方案

热门文章

  1. 如何连动作导入3dmax_教你如何将犀牛(Rhino)模型导入3dmax并进行渲染
  2. springboot中使用websocket_Spring Boot中Lombok使用
  3. Python笔记-BeautifulSoup中find_all的使用及str中trim()
  4. Qt工作笔记-信号与槽参数匹配问题
  5. C/C++之win98扫雷外挂基础篇
  6. mysql语句编码_使用SQL语句操作MYSQL字符编码
  7. ar android app,RakugakiAR安卓版
  8. Java游戏触屏处理,非触屏java游戏转换为触屏游戏工具使用方法
  9. thread local性能 c++_MySQL 5.7 amp; MySQL 8.0 性能对比
  10. linux 物理内存用完了_调整linux内核尽量用内存,而不用swap