之前的链表就是一个普通的带头的单向链表,我们不自觉的会发现这样的链表有缺陷,有关链表的删除新增查找跟链表的结构体内容耦合性太强

什么意思呢?

比如我们之前的链表的结构体

  1. typedef struct _Teacher
  2. {
  3. int age;
  4. struct _Teacher *next;
  5. }Teacher;

我们有关链表所有的操作都跟这个结构体紧密的相连,如果此刻我们有另一个结构体,里面的字段都跟这个不一样,那么,我们可能还需要对这个新的结构体写一套链表操作?

相当于下面的图,呵呵,有点丑

那么我们的解决方案是什么呢?,我们能不能关于不同结构体的所有操作都有一套公共方法呢?

当然是可以的!

在这之前我们必须有一个概念,结构体中的第一个元素的地址就是代表结构体的地址。

我们设计一个单纯代表数据结构的结构体,这个结构体只有下个对象的地址的指针成员

  1. typedef struct _tag_LinkListNode
  2. {
  3. void * next;
  4. }LinkListNode;

比如此刻我们有一个教师结构体,那么我们只需要在结构体的第一个成员是上面的LinkListNode对象。
形成下面的数据结构:

  1. typedef struct _Teacher
  2. {
  3. LinkListNode listNode;
  4. int age;
  5. char name[];
  6. }Teacher;

那么,此刻我们只要在我们的对链表的操作将传过来的Teacher * 指针强转为LinkListNode *类型,查询出来的LinkListNode * 指针变量再强转为Teacher * 对象,从而对LinkListNode形成一套插入删除查询的api就可以了
以下是实现的代码:

接口:

  1. #ifndef _MYLINKLIST_H_
  2. #define _MYLINKLIST_H_
  3.  
  4. typedef void LinkList;
  5.  
  6. typedef struct _tag_LinkListNode
  7. {
  8. struct _tag_LinkListNode* next;
  9. }LinkListNode;
  10.  
  11. LinkList* LinkList_Create();
  12.  
  13. void LinkList_Destroy(LinkList* list);
  14.  
  15. void LinkList_Clear(LinkList* list);
  16.  
  17. int LinkList_Length(LinkList* list);
  18.  
  19. int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
  20.  
  21. LinkListNode* LinkList_Get(LinkList* list, int pos);
  22.  
  23. LinkListNode* LinkList_Delete(LinkList* list, int pos);
  24.  
  25. #endif

实现:

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "linklist.h"
  4.  
  5. typedef struct _tag_LinkList
  6. {
  7. //头节点
  8. LinkListNode header;
  9. int length;
  10. }TLinkList;
  11.  
  12. /************************************************************************/
  13. /* 创建list并初始化一个头节点 */
  14. /************************************************************************/
  15. LinkList* LinkList_Create()
  16. {
  17. TLinkList *tlist = (TLinkList *)malloc(sizeof(TLinkList));
  18. if (tlist == NULL)
  19. {
  20. return NULL;
  21. }
  22. tlist->length = ;
  23. tlist->header.next = NULL;
  24. return tlist;
  25. }
  26.  
  27. void LinkList_Destroy(LinkList* list)
  28. {
  29. if (list == NULL)
  30. {
  31. return;
  32. }
  33. free(list);
  34. }
  35. /************************************************************************/
  36. /* 清空list链表 */
  37. /************************************************************************/
  38. void LinkList_Clear(LinkList* list)
  39. {
  40. if (list == NULL)
  41. {
  42. return;
  43. }
  44. TLinkList *tlinkList = (TLinkList *)list;
  45. tlinkList->length = ;
  46. tlinkList->header.next = NULL;
  47.  
  48. }
  49.  
  50. int LinkList_Length(LinkList* list)
  51. {
  52. if (list == NULL)
  53. {
  54. return ;
  55. }
  56. TLinkList *tlinkList = (TLinkList *)list;
  57.  
  58. return tlinkList->length;
  59. }
  60.  
  61. int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
  62. {
  63. LinkListNode *pre, *cur;
  64. int i;
  65. if (list == NULL || node == NULL)
  66. {
  67. return -;
  68. }
  69. //校验下标
  70. if (pos<)
  71. {
  72. return -;
  73. }
  74. TLinkList *tlinkList = (TLinkList *)list;
  75. if (pos>tlinkList->length - )
  76. {
  77. pos = tlinkList->length;
  78. }
  79. pre = (LinkListNode *)list;//初始化指向头节点
  80. cur = tlinkList->header.next;//初始化指向第一个节点,如果空链表指向空
  81. for (i = ; i < pos; i++)
  82. {
  83. pre = cur;
  84. cur = cur->next;//最终让当前指针指向要插入的位置
  85. }
  86. pre->next = node;
  87. node->next = cur;
  88.  
  89. tlinkList->length++;
  90. return ;
  91. }
  92.  
  93. LinkListNode* LinkList_Get(LinkList* list, int pos)
  94. {
  95. LinkListNode *pre, *cur;
  96. int i;
  97. if (list == NULL)
  98. {
  99. return NULL;
  100. }
  101. TLinkList *tlinkList = (TLinkList *)list;
  102. //校验下标
  103. if (pos >= tlinkList->length || pos < )
  104. {
  105. return NULL;
  106. }
  107. cur = tlinkList->header.next;//初始化指向第一个节点,如果空链表指向空
  108. for (i = ; i < pos; i++)
  109. {
  110. cur = cur->next;
  111. }
  112.  
  113. return cur;
  114. }
  115.  
  116. LinkListNode* LinkList_Delete(LinkList* list, int pos)
  117. {
  118. LinkListNode *pre, *cur;
  119. int i;
  120. if (list == NULL)
  121. {
  122. return NULL;
  123. }
  124. TLinkList *tlinkList = (TLinkList *)list;
  125. //校验下标
  126. if (pos >= tlinkList->length || pos < )
  127. {
  128. return NULL;
  129. }
  130. pre = (LinkListNode *)list;//初始化指向头节点
  131. cur = tlinkList->header.next;//初始化指向第一个节点,如果空链表指向空
  132. for (i = ; i < pos; i++)
  133. {
  134. pre = cur;
  135. cur = cur->next;
  136. }
  137. pre->next = cur->next;
  138. LinkListNode* curnode = cur;
  139. tlinkList->length--;
  140. return curnode;
  141. }

测试代码

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "linklist.h"
  4.  
  5. typedef struct _Teacher
  6. {
  7. LinkListNode listNode;
  8. int age;
  9. char name[];
  10. }Teacher;
  11. void main()
  12. {
  13. LinkList* linkList;
  14. Teacher t1, t2, t3;
  15. int len;
  16. int i;
  17. linkList = LinkList_Create();
  18. t1.age = ;
  19. t2.age = ;
  20. t3.age = ;
  21. LinkList_Insert(linkList, (LinkListNode*)&t1, );
  22. LinkList_Insert(linkList, (LinkListNode*)&t2, );
  23. LinkList_Insert(linkList, (LinkListNode*)&t3, );
  24.  
  25. len = LinkList_Length(linkList);
  26.  
  27. for (i = ; i < len; i++)
  28. {
  29. Teacher * t = (Teacher *)LinkList_Get(linkList, i);
  30. printf("cur teacher age=%d\n", t->age);
  31. }
  32.  
  33. LinkList_Delete(linkList, );
  34. LinkList_Delete(linkList, );
  35. len = LinkList_Length(linkList);
  36. for (i = ; i < len; i++)
  37. {
  38. Teacher * t = (Teacher *)LinkList_Get(linkList, i);
  39. printf("cur teacher age=%d\n", t->age);
  40. }
  41. system("pause");
  42.  
  43. }

接下来,如果我们有新的结构体,只要在测试代码那边做修改,而不需要动我们的核心代码了。

c语言链表升级的更多相关文章

  1. C语言 链表

    原文:C语言 链表 最近在复习数据结构,想把数据结构里面涉及的都自己实现一下,完全是用C语言实现的. 自己编写的不是很好,大家可以参考,有错误希望帮忙指正,现在正处于编写阶段,一共将要实现19个功能. ...

  2. C语言链表操作模板(添加,删除,遍历,排序)

    C语言链表操作模板,摘自郝斌的C语言视频教程,简单的修改成了纯C格式.当年照着视频学习的时候记录下来的,在使用的时候直接拿来修改修改修改能节约不少时间的. /********************* ...

  3. ZT C语言链表操作(新增单向链表的逆序建立)

    这个不好懂,不如看 转贴:C语言链表基本操作http://www.cnblogs.com/jeanschen/p/3542668.html ZT 链表逆序http://www.cnblogs.com/ ...

  4. C语言链表结构体(学习笔记)

    #include <stdio.h> #define LENTEST 100 // 采取逐步删除的方法求的素数 //先假设1-100都是素数,然后剔除2的倍数, //3的倍数,直到剔除所有 ...

  5. C语言链表实例--玩转链表

    下图为最一简单链表的示意图: 第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量.以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号 num,姓名 n ...

  6. c语言-链表VS数组

    数组和链表的区别   数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素.但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要 ...

  7. 再次复习数据结构:c语言链表的简单操作

    最近呢,又要面临多次的数据结构与算法方面的试题了,而我呢,大概也重新温习c语言的基本要点快一个月了,主要是针对指针这货的角度在研究c语言,感觉又学到了不少. 现在c指针感觉知道点了,也就匆忙开展数据结 ...

  8. [数据结构]C语言链表实现

    我学数据结构的时候也是感觉很困难,当我学完后我发现了之所以困难时因为我没有系统的进行学习,而且很多教授都只是注重数据结构思想,而忽略了代码方面,为此我写了这些博文给那些试图自学数据结构的朋友,希望你们 ...

  9. [C语言]链表实现贪吃蛇及部分模块优化

    在继上篇[C语言]贪吃蛇_结构数组实现大半年后,链表实现的版本也终于出炉了.两篇隔了这么久除了是懒癌晚期的原因外,对整个游戏流程的改进,模块的精简也花了一些时间(都是借口). 优化模块的前沿链接: · ...

随机推荐

  1. 验证表格多行某一input是否为空

    function checkTableKeyWordVal(tableId){ var result = true; $("#"+tableId+" tbody tr&q ...

  2. php第三方类库定时任务

    <?php /** * Created by PhpStorm. * User: hanks * Date: 5/27/2017 * Time: 3:11 PM */ //2 .常驻内存的各种P ...

  3. 基于 HTML5 WebGL 的 3D 网络拓扑图

    在数据量很大的2D 场景下,要找到具体的模型比较困难,并且只能显示出模型的的某一部分,显示也不够直观,这种时候能快速搭建出 3D 场景就有很大需求了.但是搭建 3D 应用场景又依赖于通过 3ds Ma ...

  4. 15个必须知道的 Chrome 开发技巧

    在 Web 开发者中,Chrome 是使用最广泛的浏览器.六周一次的发布周期和一套强大的不断扩大开发功能,使其成为了web开发者必备的工具.你可能已经熟悉了它的部分功能,如使用 console 和 d ...

  5. 使用base64提升视觉效果体验

    最近在做一个微信端的小项目,前端代码写完后,就放在手机端测试,没什么问题,但是页面在加载和渲染时的效果却让人有些不爽,虽然是个小项目,我大可不必做这些,但是看着页面的闪动,就忍不住想做些什么. 先说说 ...

  6. MySQL慢查询日志

    实验环境: OS X EI Captian + MySQL 5.7 一.配置MySQL自动记录慢查询日志 查看变量,也就是配置信息 show (global) variables like '%slo ...

  7. 本地服务器 windows server 2008 datacenter conn /as sysdba 提示 ora-01031 insufficient privileges

    原因是需要把当前用户administrator(为例)添加到ora_dba组里. 服务器管理器--配置--本地用户和组--组

  8. spring +springmvc+mybatis组合web.xml文件配置

    <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://w ...

  9. [随笔]_ELVE_git命令复习

    mkdir: XX (创建一个空目录 XX指目录名) pwd: 显示当前目录的路径. git init 把当前的目录变成可以管理的git仓库,生成隐藏.git文件. git add XX 把xx文件添 ...

  10. Oracle索引批量重置笔记

    ---单个索引重置语句 alter index indexname  rebuild; ---查询数据索引对象语句 select *  from user_indexes; ------将数据库的索引 ...