C语言实现双向链表
文章目录
1. 抽象数据类型定义
定义链表节点结构,链表结构,链表迭代器结构,链表迭代器方向枚举
/*
* list_t node struct.
*/
typedef struct list_node {
struct list_node *prev;
struct list_node *next;
void *val;
} list_node_t;
/*
* list_t struct.
*/
typedef struct {
list_node_t *head;
list_node_t *tail;
unsigned int len;
void (*free)(void *val);
int (*match)(void *a, void *b);
} list_t;
/*
* list_t iterator struct.
*/
typedef struct {
list_node_t *next;
list_direction_t direction;
} list_iterator_t;
/*
* list_t iterator direction.
*/
typedef enum {
LIST_HEAD,
LIST_TAIL
} list_direction_t;
2. API设计
双向链表对外提供接口,节点元素创建,链表创建/销毁,插入元素,删除元素,查找元素,迭代器创建/销毁
#ifndef LIST_H
#define LIST_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#ifndef LIST_MALLOC
#define LIST_MALLOC malloc
#endif
#ifndef LIST_FREE
#define LIST_FREE free
#endif
list_node_t* list_node_new(void *val);
list_t* list_new();
list_node_t* list_rpush(list_t *self, list_node_t *node);
list_node_t* list_lpush(list_t *self, list_node_t *node);
list_node_t* list_find(list_t *self, void *val);
list_node_t* list_at(list_t *self, int index);
list_node_t* list_rpop(list_t *self);
list_node_t* list_lpop(list_t *self);
void list_remove(list_t *self, list_node_t *node);
void list_destroy(list_t *self);
list_iterator_t* list_iterator_new(list_t *list, list_direction_t direction);
list_iterator_t* list_iterator_new_from_node(list_node_t *node, list_direction_t direction);
list_node_t* list_iterator_next(list_iterator_t *self);
void list_iterator_destroy(list_iterator_t *self);
#ifdef __cplusplus
}
#endif
#endif /* LIST_H */
3. 接口实现
3.1 节点元素创建
list_node_t* list_node_new(void *val) {
list_node_t *self;
if (!(self = LIST_MALLOC(sizeof(list_node_t))))
return NULL;
self->prev = NULL;
self->next = NULL;
self->val = val;
return self;
}
3.2 链表创建/销毁
//链表的创建
list_t *list_new() {
list_t *self = NULL;
if (!(self = LIST_MALLOC(sizeof(list_t))))
return NULL;
self->head = NULL;
self->tail = NULL;
self->free = NULL;
self->match = NULL;
self->len = 0;
return self;
}
//链表的销毁
void list_destroy(list_t *self) {
if (!self)
return;
unsigned int len = self->len;
list_node_t *next = NULL;
list_node_t *curr = self->head;
while (len--) {
next = curr->next;
if (self->free) self->free(curr->val);
LIST_FREE(curr);
curr = next;
}
LIST_FREE(self);s
}
3.3 插入元素
- 链表尾部插入元素
- 链表头部插入元素
//链表尾部插入元素
list_node_t* list_rpush(list_t *self, list_node_t *node) {
if (!node) return NULL;
if (self->len) {
node->prev = self->tail;
node->next = NULL;
self->tail->next = node;
self->tail = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
//链表头部插入元素
list_node_t* list_lpush(list_t *self, list_node_t *node) {
if (!node || !self) return NULL;
if (self->len) {
node->next = self->head;
node->prev = NULL;
self->head->prev = node;
self->head = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
3.4 删除元素
- 尾部删除
- 头部删除
- 删除链表中的给定节点
//尾部删除
list_node_t* list_rpop(list_t *self) {
if (!self)
return NULL;
if (!self->len) return NULL;
list_node_t *node = self->tail;
if (--self->len) {
(self->tail = node->prev)->next = NULL;
} else {
self->tail = self->head = NULL;
}
node->next = node->prev = NULL;
return node;
}
//头部删除
list_node_t* list_lpop(list_t *self) {
if (!self)
return NULL;
if (!self->len) return NULL;
list_node_t *node = self->head;
if (--self->len) {
(self->head = node->next)->prev = NULL;
} else {
self->head = self->tail = NULL;
}
node->next = node->prev = NULL;
return node;
}
//给定链表头指针和节点指针,删除节点
void list_remove(list_t *self, list_node_t *node) {
node->prev
? (node->prev->next = node->next)
: (self->head = node->next);
node->next
? (node->next->prev = node->prev)
: (self->tail = node->prev);
if (self->free) self->free(node->val);
LIST_FREE(node);
--self->len;
}
3.5 迭代器创建/销毁
//迭代器创建
//Param: 给定链表指针
// 迭代器方向
list_iterator_t* list_iterator_new(list_t *list, list_direction_t direction) {
list_node_t *node = direction == LIST_HEAD
? list->head
: list->tail;
return list_iterator_new_from_node(node, direction);
}
//迭代器创建
//Param: 链表节点指针
// 迭代器方向
list_iterator_t* list_iterator_new_from_node(list_node_t *node, list_direction_t direction) {
list_iterator_t *self;
if (!(self = LIST_MALLOC(sizeof(list_iterator_t))))
return NULL;
self->next = node;
self->direction = direction;
return self;
}
//寻找下一个节点
list_node_t* list_iterator_next(list_iterator_t *self) {
list_node_t *curr = self->next;
if (curr) {
self->next = self->direction == LIST_HEAD
? curr->next
: curr->prev;
}
return curr;
}
//销毁迭代器
void list_iterator_destroy(list_iterator_t *self) {
LIST_FREE(self);
self = NULL;
}
3.6 查找元素
- 通过给定的内容查找链表中的节点
- 查找链表中给定下标的节点
//通过给定的内容查找链表中的节点
list_node_t* list_find(list_t *self, void *val) {
list_iterator_t *it = list_iterator_new(self, LIST_HEAD);
list_node_t *node;
while ((node = list_iterator_next(it))) {
if (self->match) {
if (self->match(val, node->val)) {
list_iterator_destroy(it);
return node;
}
} else {
if (val == node->val) {
list_iterator_destroy(it);
return node;
}
}
}
list_iterator_destroy(it);
return NULL;
}
//查找链表中给定下标的节点
list_node_t* list_at(list_t *self, int index) {
list_direction_t direction = LIST_HEAD;
if (index < 0) {
direction = LIST_TAIL;
index = ~index;
}
if ((unsigned)index < self->len) {
list_iterator_t *it = list_iterator_new(self, direction);
list_node_t *node = list_iterator_next(it);
while (index--) node = list_iterator_next(it);
list_iterator_destroy(it);
return node;
}
return NULL;
}
4. 测试
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "list.h"
#define test(fn) \
puts("... " # fn ": \t CALL OK!"); \
test_##fn();
static int freeProxyCalls = 0;
void freeProxy(void *val) {
++freeProxyCalls;
free(val);
}
typedef struct {
char *name;
} User;
static int User_equal(User *a, User *b) {
return 0 == strcmp(a->name, b->name);
}
// Tests
static void test_list_node_new() {
char *val = "some value";
list_node_t *node = list_node_new(val);
assert(node->val == val);
free(node);
}
static void test_list_rpush() {
// Setup
list_t *list = list_new();
list_node_t *a = list_node_new("a");
list_node_t *b = list_node_new("b");
list_node_t *c = list_node_new("c");
// a b c
list_rpush(list, a);
list_rpush(list, b);
list_rpush(list, c);
// Assertions
assert(a == list->head);
assert(c == list->tail);
assert(3 == list->len);
assert(b == a->next);
assert(NULL == a->prev);
assert(c == b->next);
assert(a == b->prev);
assert(NULL == c->next);
assert(b == c->prev);
list_destroy(list);
}
static void test_list_lpush() {
// Setup
list_t *list = list_new();
list_node_t *a = list_node_new("a");
list_node_t *b = list_node_new("b");
list_node_t *c = list_node_new("c");
// c b a
list_rpush(list, a);
list_lpush(list, b);
list_lpush(list, c);
// Assertions
assert(c == list->head);
assert(a == list->tail);
assert(3 == list->len);
assert(NULL == a->next);
assert(b == a->prev);
assert(a == b->next);
assert(c == b->prev);
assert(b == c->next);
assert(NULL == c->prev);
list_destroy(list);
}
static void test_list_at() {
// Setup
list_t *list = list_new();
list_node_t *a = list_node_new("a");
list_node_t *b = list_node_new("b");
list_node_t *c = list_node_new("c");
// a b c
list_rpush(list, a);
list_rpush(list, b);
list_rpush(list, c);
// Assertions
assert(a == list_at(list, 0));
assert(b == list_at(list, 1));
assert(c == list_at(list, 2));
assert(NULL == list_at(list, 3));
assert(c == list_at(list, -1));
assert(b == list_at(list, -2));
assert(a == list_at(list, -3));
assert(NULL == list_at(list, -4));
list_destroy(list);
}
static void test_list_destroy() {
// Setup
list_t *a = list_new();
list_destroy(a);
// a b c
list_t *b = list_new();
list_rpush(b, list_node_new("a"));
list_rpush(b, list_node_new("b"));
list_rpush(b, list_node_new("c"));
list_destroy(b);
// Assertions
list_t *c = list_new();
c->free = freeProxy;
list_rpush(c, list_node_new(list_node_new("a")));
list_rpush(c, list_node_new(list_node_new("b")));
list_rpush(c, list_node_new(list_node_new("c")));
list_destroy(c);
assert(3 == freeProxyCalls);
}
static void test_list_find() {
// Setup
list_t *langs = list_new();
list_node_t *js = list_rpush(langs, list_node_new("js"));
list_node_t *ruby = list_rpush(langs, list_node_new("ruby"));
list_t *users = list_new();
users->match = User_equal;
User userTJ = { "tj" };
User userSimon = { "simon" };
User userTaylor = { "taylor" };
list_node_t *tj = list_rpush(users, list_node_new(&userTJ));
list_node_t *simon = list_rpush(users, list_node_new(&userSimon));
// Assertions
list_node_t *a = list_find(langs, "js");
list_node_t *b = list_find(langs, "ruby");
list_node_t *c = list_find(langs, "foo");
assert(js == a);
assert(ruby == b);
assert(NULL == c);
list_destroy(langs);
a = list_find(users, &userTJ);
b = list_find(users, &userSimon);
c = list_find(users, &userTaylor);
assert(tj == a);
assert(simon == b);
assert(NULL == c);
list_destroy(users);
}
static void test_list_remove() {
// Setup
list_t *list = list_new();
list_node_t *a = list_rpush(list, list_node_new("a"));
list_node_t *b = list_rpush(list, list_node_new("b"));
list_node_t *c = list_rpush(list, list_node_new("c"));
// Assertions
assert(3 == list->len);
list_remove(list, b);
assert(2 == list->len);
assert(a == list->head);
assert(c == list->tail);
assert(c == a->next);
assert(NULL == a->prev);
assert(NULL == c->next);
assert(a == c->prev);
list_remove(list, a);
assert(1 == list->len);
assert(c == list->head);
assert(c == list->tail);
assert(NULL == c->next);
assert(NULL == c->prev);
list_remove(list, c);
assert(0 == list->len);
assert(NULL == list->head);
assert(NULL == list->tail);
list_destroy(list);
}
static void test_list_rpop() {
// Setup
list_t *list = list_new();
list_node_t *a = list_rpush(list, list_node_new("a"));
list_node_t *b = list_rpush(list, list_node_new("b"));
list_node_t *c = list_rpush(list, list_node_new("c"));
// Assertions
assert(3 == list->len);
assert(c == list_rpop(list));
assert(2 == list->len);
assert(a == list->head);
assert(b == list->tail);
assert(a == b->prev);
assert(NULL == list->tail->next && "new tail node next is not NULL");
assert(NULL == c->prev && "detached node prev is not NULL");
assert(NULL == c->next && "detached node next is not NULL");
free(c);
assert(b == list_rpop(list));
assert(1 == list->len);
assert(a == list->head);
assert(a == list->tail);
free(b);
assert(a == list_rpop(list));
assert(0 == list->len);
assert(NULL == list->head);
assert(NULL == list->tail);
free(a);
assert(NULL == list_rpop(list));
assert(0 == list->len);
list_destroy(list);
}
static void test_list_lpop() {
// Setup
list_t *list = list_new();
list_node_t *a = list_rpush(list, list_node_new("a"));
list_node_t *b = list_rpush(list, list_node_new("b"));
list_node_t *c = list_rpush(list, list_node_new("c"));
// Assertions
assert(3 == list->len);
assert(a == list_lpop(list));
assert(2 == list->len);
assert(b == list->head);
assert(NULL == list->head->prev && "new head node prev is not NULL");
assert(NULL == a->prev && "detached node prev is not NULL");
assert(NULL == a->next && "detached node next is not NULL");
free(a);
assert(b == list_lpop(list));
assert(1 == list->len);
free(b);
assert(c == list_lpop(list));
assert(0 == list->len);
assert(NULL == list->head);
assert(NULL == list->tail);
free(c);
assert(NULL == list_lpop(list));
assert(0 == list->len);
list_destroy(list);
}
static void test_list_iterator_t() {
// Setup
list_t *list = list_new();
list_node_t *tj = list_node_new("tj");
list_node_t *taylor = list_node_new("taylor");
list_node_t *simon = list_node_new("simon");
// tj taylor simon
list_rpush(list, tj);
list_rpush(list, taylor);
list_rpush(list, simon);
// Assertions
// From head
list_iterator_t *it = list_iterator_new(list, LIST_HEAD);
list_node_t *a = list_iterator_next(it);
list_node_t *b = list_iterator_next(it);
list_node_t *c = list_iterator_next(it);
list_node_t *d = list_iterator_next(it);
assert(a == tj);
assert(b == taylor);
assert(c == simon);
assert(NULL == d);
list_iterator_destroy(it);
// From tail
it = list_iterator_new(list, LIST_TAIL);
list_node_t *a2 = list_iterator_next(it);
list_node_t *b2 = list_iterator_next(it);
list_node_t *c2 = list_iterator_next(it);
list_node_t *d2 = list_iterator_next(it);
assert(a2 == simon);
assert(b2 == taylor);
assert(c2 == tj);
assert(NULL == d2);
list_iterator_destroy(it);
list_destroy(list);
}
int main(void){
printf("\nlist_t: %ld\n", sizeof(list_t));
printf("list_node_t: %ld\n", sizeof(list_node_t));
printf("list_iterator_t: %ld\n\n", sizeof(list_iterator_t));
test(list_node_new);
test(list_rpush);
test(list_lpush);
test(list_find);
test(list_at);
test(list_remove);
test(list_rpop);
test(list_lpop);
test(list_destroy);
test(list_iterator_t);
puts("... CALL END ...");
return 0;
}
运行输出 :
list_t: 20
list_node_t: 12
list_iterator_t: 8
... list_node_new: CALL OK!
... list_rpush: CALL OK!
... list_lpush: CALL OK!
... list_find: CALL OK!
... list_at: CALL OK!
... list_remove: CALL OK!
... list_rpop: CALL OK!
... list_lpop: CALL OK!
... list_destroy: CALL OK!
... list_iterator_t: CALL OK!
... CALL END ...