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

什么意思呢?

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

typedef struct _Teacher
{
int age;
struct _Teacher *next;
}Teacher;

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

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

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

当然是可以的!

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

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

typedef struct _tag_LinkListNode
{
void * next;
}LinkListNode;

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

typedef struct _Teacher
{
LinkListNode listNode;
int age;
char name[];
}Teacher;

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

接口:

#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_ typedef void LinkList; typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode* next;
}LinkListNode; LinkList* LinkList_Create(); void LinkList_Destroy(LinkList* list); void LinkList_Clear(LinkList* list); int LinkList_Length(LinkList* list); int LinkList_Insert(LinkList* list, LinkListNode* node, int pos); LinkListNode* LinkList_Get(LinkList* list, int pos); LinkListNode* LinkList_Delete(LinkList* list, int pos); #endif

实现:

#include "stdio.h"
#include "stdlib.h"
#include "linklist.h" typedef struct _tag_LinkList
{
//头节点
LinkListNode header;
int length;
}TLinkList; /************************************************************************/
/* 创建list并初始化一个头节点 */
/************************************************************************/
LinkList* LinkList_Create()
{
TLinkList *tlist = (TLinkList *)malloc(sizeof(TLinkList));
if (tlist == NULL)
{
return NULL;
}
tlist->length = ;
tlist->header.next = NULL;
return tlist;
} void LinkList_Destroy(LinkList* list)
{
if (list == NULL)
{
return;
}
free(list);
}
/************************************************************************/
/* 清空list链表 */
/************************************************************************/
void LinkList_Clear(LinkList* list)
{
if (list == NULL)
{
return;
}
TLinkList *tlinkList = (TLinkList *)list;
tlinkList->length = ;
tlinkList->header.next = NULL; } int LinkList_Length(LinkList* list)
{
if (list == NULL)
{
return ;
}
TLinkList *tlinkList = (TLinkList *)list; return tlinkList->length;
} int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
LinkListNode *pre, *cur;
int i;
if (list == NULL || node == NULL)
{
return -;
}
//校验下标
if (pos<)
{
return -;
}
TLinkList *tlinkList = (TLinkList *)list;
if (pos>tlinkList->length - )
{
pos = tlinkList->length;
}
pre = (LinkListNode *)list;//初始化指向头节点
cur = tlinkList->header.next;//初始化指向第一个节点,如果空链表指向空
for (i = ; i < pos; i++)
{
pre = cur;
cur = cur->next;//最终让当前指针指向要插入的位置
}
pre->next = node;
node->next = cur; tlinkList->length++;
return ;
} LinkListNode* LinkList_Get(LinkList* list, int pos)
{
LinkListNode *pre, *cur;
int i;
if (list == NULL)
{
return NULL;
}
TLinkList *tlinkList = (TLinkList *)list;
//校验下标
if (pos >= tlinkList->length || pos < )
{
return NULL;
}
cur = tlinkList->header.next;//初始化指向第一个节点,如果空链表指向空
for (i = ; i < pos; i++)
{
cur = cur->next;
} return cur;
} LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
LinkListNode *pre, *cur;
int i;
if (list == NULL)
{
return NULL;
}
TLinkList *tlinkList = (TLinkList *)list;
//校验下标
if (pos >= tlinkList->length || pos < )
{
return NULL;
}
pre = (LinkListNode *)list;//初始化指向头节点
cur = tlinkList->header.next;//初始化指向第一个节点,如果空链表指向空
for (i = ; i < pos; i++)
{
pre = cur;
cur = cur->next;
}
pre->next = cur->next;
LinkListNode* curnode = cur;
tlinkList->length--;
return curnode;
}

测试代码

#include "stdio.h"
#include "stdlib.h"
#include "linklist.h" typedef struct _Teacher
{
LinkListNode listNode;
int age;
char name[];
}Teacher;
void main()
{
LinkList* linkList;
Teacher t1, t2, t3;
int len;
int i;
linkList = LinkList_Create();
t1.age = ;
t2.age = ;
t3.age = ;
LinkList_Insert(linkList, (LinkListNode*)&t1, );
LinkList_Insert(linkList, (LinkListNode*)&t2, );
LinkList_Insert(linkList, (LinkListNode*)&t3, ); len = LinkList_Length(linkList); for (i = ; i < len; i++)
{
Teacher * t = (Teacher *)LinkList_Get(linkList, i);
printf("cur teacher age=%d\n", t->age);
} LinkList_Delete(linkList, );
LinkList_Delete(linkList, );
len = LinkList_Length(linkList);
for (i = ; i < len; i++)
{
Teacher * t = (Teacher *)LinkList_Get(linkList, i);
printf("cur teacher age=%d\n", t->age);
}
system("pause"); }

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

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. C++数组概述

    C++数组概述 基本概念 1. 数组是固定大小的一种复合类型 因为数组是固定大小,所以在编译期间就决定了基大小 数组的内存是连续(无论是一维数组还是多维数组) 2. 数组的特性 数组之间不允许拷贝和赋 ...

  2. JavaScript浮点运算的问题 (乘法)

    <script type="text/javascript"> var get_b_val_final=accMul(get_b_val,100)+"%&qu ...

  3. flask 上传头像

    上传头像,自己感觉了好久,就是上传文件呗其实,存在一个路径,数据库存储这个路径,然后展示给前端,啥都不说,看怎么实现的. 数据库设置如下 user_image=db.Column(db.String( ...

  4. 一张图告诉你angular2所有知识点

    忙活了半年,从angular2.0到现在angular4.2.从没AOT到有AOT.我想说,angular2的学习曲线真的有点陡峭.只能说,angular2是一个比较完整的框架,框架就是这样,一大堆条 ...

  5. phpstorm,webstorm取消自动保存并标识修改的文件为星星标记

    a.取消自动保存是去掉一下两个勾选. b.标记星星要勾选下面的选项.

  6. Android Studio 运行java程序

    当我们装了Android Studio 学习安卓开发的时候,难免会要学习java,这时候,难道在重新装一个编译器吗?不需要,我们直接用 Android Studio 就可以. 1.新建一个空项目,选择 ...

  7. 多个Tomcat 配置多个JDK

  8. VB6之调整任务栏按钮的位置

    好无聊,睡前一更~ XP的任务栏没办法像win7那样随意拖动交换顺序,偶觉不爽,遂写程序搞之.这个不算什么新东西,参考了很多别人写的东东. 程序启动后,会在右下角托盘区显示钢铁侠的图标.右键击之,可选 ...

  9. IE过滤器

    1.  _ 下划线属性过滤器  语法:_选择符{属性:属性值}   2. *通配符属性过滤器 语法:*选择符{属性:属性值}   3.  \9: IE版本识别:其他浏览器都不识别 语法:选择符{属性: ...

  10. 欢迎大家Follow me!微软MVP罗勇(Dynamics CRM方向)欢迎您!

    我是一名八零后,来自湖南乡村,2002年毕业于大连大学工商管理专业,主要靠自学走上了编程之路.从2012年开始接触Dynamics CRM 2011,一直从事Dynamics CRM方面工作,熟悉Dy ...