链表

来源:互联网 发布:幼儿园软件 编辑:程序博客网 时间:2024/05/19 16:50

链表作为一种最为基础的数据机构,在C语言中竟然没有它的标准实现。如果每次编写程序遇到需要使用线性存储结构时都需要手打一遍链表,对编程体验绝对是一种伤害。

令我很惊讶的是,C语言没有类似于C++的STL库。linux源代码中提供了C版本list的优雅实现,但竟然无法直接在应用层代码中直接使用#include <linux/list.h>,就算是移植也要费很大的劲。

本文回顾一下链表的基本概念,为手打代码打下基础。然后给出一份实现代码备用,最后分析一下C++标准库中的std::list.



单链表:


(图片来自《算法精解》)

它分为:

1,链表头,

2,链表成员:

2.1数据域

2.2 next指针。

尽管有些实现里没有链表头,直接使用链表元素当链表头。但维护一个链表头还是有很多好处的。可以记录着链表的长度,可以记录链表的头指针和尾指针。甚至为了数据抽象方便,还可以维护一个用于查找的比较函数(可选),和用来释放内存的destroy函数(可选)


//链表头的C语言实现代码typedef struct List_ {int size; //链表大小int (*match)(const void *key1, const void *key2);//比较函数,允许为NULLvoid (*destroy)(void *data);//内存释放函数,允许为NULLListElmt *head;ListElmt *tail;} List;


//链表的元素定义typedef struct ListElmt_ { void *data;struct ListElmt_ *next;} ListElmt;

需要注意链表元素的生命周期,一般用法是存放malloc出来的堆变量,谨慎使用局部栈变量---它将会是万恶之源。


链表的操作函数有:

void list_init(List *list, void (*destroy)(void *data));void list_destroy(List *list);int list_ins_next(List *list, ListElmt *element, const void *data);int list_rem_next(List *list, ListElmt *element, void **data);

链表在使用之前必须要先初始化,用来初始化链表头。

void list_init(List *list, void (*destroy)(void *data)) {list->size = 0;list->destroy = destroy;list->head = NULL;list->tail = NULL;return;}


链表使用之后,需要销毁链表
void list_destroy(List *list) {void *data;while (list_size(list) > 0) {if (list_rem_next(list, NULL, (void **)&data) == 0 && list->destroy != NULL) {list->destroy(data);}}
memset(list, 0, sizeof(List));
return;
}



链表的插入和删除部分的代码,是链表的精华。

先看插入



int list_ins_next(List *list, ListElmt *element, const void *data) {    ListElmt *new_element;    if ((new_element = (ListElmt *)malloc(sizeof(ListElmt))) == NULL)        return -1;    new_element->data = (void *)data;    if (element == NULL) {        if (list_size(list) == 0) {            list->tail = new_element;        }        new_element->next = list->head;        list->head = new_element;    }    else {        if (element->next == NULL) {            list->tail = new_element;        }        new_element->next = element->next;        element->next = new_element;    }    list->size++;    return 0;}

再看看链表节点的删除


int list_rem_next(List *list, ListElmt *element, void **data) {    ListElmt           *old_element;    if (list_size(list) == 0)        return -1;    if (element == NULL) {        *data = list->head->data;        old_element = list->head;        list->head = list->head->next;        if (list_size(list) == 1)            list->tail = NULL;    } else {        if (element->next == NULL)            return -1;        *data = element->next->data;        old_element = element->next;        element->next = element->next->next;        if (element->next == NULL)            list->tail = element;    }    free(old_element);    list->size--;    return 0;}

以上代码和图片来自《算法精解》
}
0 0