设为首页 加入收藏

TOP

使用C语言实现“泛型”链表(二)
2014-02-08 12:43:39 来源: 作者: 【 】 浏览:600
Tags:使用 语言 实现 泛型 链表

 

  //返回list中第index个数据的指针

  void* At(List list, int index);

  //在begin和end之间查找符合condition的第一个元素,

  //比较函数由condition指向,比较的值由data指向

  //当第一个参数的值小于第二个参数的值时,返回1,否则返回0

  //根据condition函数的不同,可以查找第一个相等、大于或小于data的值

  Iterator FindFirst(Iterator begin, Iterator end, void *data,

  int (*condition)(const void*, const void*));

  //查找list中第一个与data相等的元素的下标,

  //equal函数,当第一个参数与第二个参数的值相等时,返回1,否则返回0

  int IndexOf(List list, void *data,

  int (*equal)(const void*,const void*));

  //查找在begin和end之间的最小值,比较函数由less指向

  //当第一个参数的值小于第二个参数的值时,返回1,否则返回0

  Iterator GetMin(Iterator begin, Iterator end,

  int (*less)(const void*, const void*));

  //查找在begin和end之间的最大值,比较函数由large指向

  //当第一个参数的值大于第二个参数的值时,返回1,否则返回0

  Iterator GetMax(Iterator begin, Iterator end,

  int (*large)(const void*, const void*));

  //获取list的长度

  int GetLength(List list);

  //若list为空链表,则返回1,否则返回0

  int IsEmpty(List list);

  //销毁list

  void DestroyList(List *list);

  //获得list的首迭代器

  Iterator Begin(List list);

  //获得list的尾迭代器,指向最后一个元素的下一个位置

  Iterator End(List list);

  //使it指向下一个位置,并返回指向下一个位置后的迭代器

  Iterator Next(Iterator *it);

  //使it指向上一个位置,并返回指向上一个位置后的迭代器

  Iterator Last(Iterator *it);

  //通过迭代器it获得数据,相当于*p

  void* GetData(Iterator it);

  //获取当前迭代器的下一个迭代器,注意,并不改变当前迭代器

  Iterator GetNext(Iterator it);

  //获取当前迭代器的上一个迭代器,注意,并不改变当前迭代器

  Iterator GetLast(Iterator it);

  为了更加清楚地表达这个链表的结构,下图所示的,就是该链表的结构:

  调用InitList函数后,链表的结构如下:

  当向链表中插入一定数量的结点后,链表的结构如下:

  三、如何实现隐藏链表的成员变量(即封装)

  首先,我们为什么需要封装呢 我觉得封装主要有三大好处。

  1)隔离变化,在程序中需要封装的通常是程序中最容易发生变化的地方,例如成员变量等,我们可以把它们封装起来,从而让它们的变化不会影响到系统的其他部分,也就是说,封装的是变化。

  2)降低复杂度,因为我们把一个对象是如何实现的等细节封装起来,只留给用户一个最小依赖的接口,从而让系统变量简单明了,在一定程度降低了系统的复杂性,方便了用户的使用。

  3)让用户只能按照我们设计好的接口来操作一个对象或类型,而不能自己直接对一个对象进行操作,从而减少了用户的误操作,提高了系统的稳定性。

  在面向对象的设计中,如果我们想要隐藏一个类的成员变量,我们可以把这些成员变量声明为私有的,而在C语言中,我们可以怎么实现呢 其实其实现是很简单的,我们在C语言中,当我们要使用一个自己定义的类型或函数时,我们会把声明它的头文件包含(include)过来,只要我们在文件中只声明其类型是一个结构体,而把它的实现写在.c文件中即可。

  在本例子中,我把struct list和struct node定义在.c文件中,而在头文件中,只声明其指针类型,即typedef struct node* Iterator和typedef struct list* List;当我们要使用该类型时,只需要在所在的文件中,include该头文件即可。因为在编译时,编译器只要知道List和Iterator是一个指针类型就能知道其所占的内存大小,也就能为其分配内存,所以能够编译成功。而又因为该头文件中并没有该类型(struct list和struct node)的定义,所以我们在使用该类型时,只能通过我们提供的接口来操作对象。例如,我们并不能使用List list; list->data等等的操作,而只能通过已定义的接口GetData来获得。

  四、如何实现泛型

  泛型,第一时间想起的可能是模板,但是在C语言中却没有这个东西。但是C语言中却有一个可以指向任何类型,在使用时,再根据具体的指针类型进行类型转换的指针类型,它就是void*。

  为什么void*可以指向任何类型的数据 这还得从C语言对于数据类型的处理方式来说明。在C语言中,我们使用malloc等函数来申请内存,而从内存的角度来看,数据是没有类型的,它们都是一串的0或1,而程序则根据不同的类型来解释这个内存单元中的数据的意义,例如对于内存中的数据,FFFFFFFF,如果它是一个有符号整型数据,它代表的是-1,而如果它是一个无符号整型数据,它代表的则是2^32-1。进一步说,如果你用一个int的指针变量p指向该内存,则*p就是-1,如果你用unsigned int的指针p指向该内存,则*p = 2^32-1。

  而我们使用malloc等函数时,也只需要说明申请的内存的大小即可,也不用说明申请的内存空间所存放的数据的类型,例如,我们申请一块内存空间来存放一个整型数据,则只需要malloc(sizeof(int)),即可,当然你完全可以把它当作一个具有4个单位的char数组来使用。所以我们可以使用void指针来指向我们申请的内存,申请内存的大小由链表中的成员data_size定义,它也是真正的data所占的内存大小。

        

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 2/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言内存泄漏之free 下一篇实现类似ping功能的C源代码

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: