看到这个标题,你可能非常惊讶,C语言也能实现泛型链表?我们知道链表是我们非常常用的数据结构,但是在C中却没有像C++中的STL那样有一个list的模板类,那么我们是否可以用C语言实现一个像STL中的list那样的泛型链表呢?答案是肯定的。下面就以本人的一个用C语言设计的链表为例子,来分析说明一下本人的设计和实现要点,希望能给你一点有用的帮助。
一、所用的链表类型的选择
我们知道,链表也有非常多的类型,包括单链表、单循环链表、双链表、双向循环链表等。在我的设计中,我的链表使用的类型是双向循环链表,并带一个不保存真实数据的头结点。其原因如下:
1)单链表由于不能从后继定位到前驱,在操作时较为不方便
2)双链表虽然能方便找到前驱,但是如果总是在其尾部插入或删除结点,为了定位的方便和操作的统一(所有的删除和插入操作,都跟在中间插入删除结点的操作一样),还要为其增加一个尾结点,并且程序还要保存一个指向这个尾结点的指针,并管理这个指针,从而增加程序的复杂性。而使用带头结点的循环双向链表,就能方便的定位(其上一个元素为链表的最后一个元素,其下一个元素为链表的第0个元素),并使所有的插入和删除的操作统一,因为头结点也是尾结点。注:结点的下标从0开始,头结点不算入下标值。
3)接口的使用与C++中stl中list和泛型算法的使用大致相同。
二、list类型的定义
为了让大家一睹为快,下面就给出这个用C语言实现的“泛型”的定义,再来说明,我这样设计的原因及要点,其定义如下:
其定义在文件list_v2.c中
typedef struct node
{
//循环双链表的结点结构
void* data;//数据域指针
struct node *next;//指向当前结点的下一结点
struct node *last;//指向当前结点的上一结点
}Node;
struct list
{
struct node *head;//头指针,指向头结点
int data_size;//链表对应的数据所占内存的大小
int length;//链表list的长度
};
其声明在文件list_v2.h中
//泛型循环双链表,带头结点,结点下标从0开始,头结点不计入下标值
//定义结点指针Node*为List类型的迭代器
typedef struct node* Iterator;
//List类型的定义
typedef struct list* List;
//初始化链表,数据域所占内存的大小由data_size给出
int InitList(List *list, int data_size);
//把data的内容插入到链表list的末尾
//assign指定数据data间的赋值方法
Iterator Append(List list, void *data,
void (*assign)(void*, const void*));
//把data的内容插入到链表的迭代器it_before的前面
//assign指定数据data间的赋值方法
Iterator Insert(List list, void *data, Iterator it_before,
void (*assign)(void*, const void*));
//把链表A中迭代器it_a指向的结点移动到链表B中迭代器it_b_befroe的前面
Iterator MoveFromAtoB(List A, Iterator it_a,
List B, Iterator it_b_before);
//删除链表list中迭代器it指向的结点
int Remove(List list, Iterator it);
//删除链表list的第0个结点,下标从0开始
int Remove