问题引入
- C 在写很多东西的时候都会牵扯到一些基础的数据结构的使用,而双向链表可以封装成好几种常用的数据结构,所以想着自己实现一个自己的双向链表,也会在以后慢慢完善此代码。
接口设计
int llist_init(d_llist_t **llist);
typedef int (*compare)(void *a, void *b);
int llist_insert(d_llist_t *llist, void *key, compare cmp);
d_llist_node_t *llist_pop_first(d_llist_t *llist);
d_llist_node_t *llist_pop_last(d_llist_t *llist);
d_llist_node_t *llist_head_look(d_llist_t *llist);
d_llist_node_t *llist_tail_look(d_llist_t *llist);
int llist_destroy(d_llist_t *llist);
typedef int (*traver)(void *node);
int llist_traver(d_llist_t *llist, traver tvr);
int llist_check(d_llist_t *llist, compare cmp);
代码
double_llist.h
#ifndef DOUBLE_LLIST__
#define DOUBLE_LLIST__
typedef void d_llist_node_t;
typedef void d_llist_t;
int llist_init(d_llist_t **llist);
typedef int (*compare)(void *a, void *b);
int llist_insert(d_llist_t *llist, void *key, compare cmp);
d_llist_node_t *llist_pop_first(d_llist_t *llist);
d_llist_node_t *llist_pop_last(d_llist_t *llist);
d_llist_node_t *llist_head_look(d_llist_t *llist);
d_llist_node_t *llist_tail_look(d_llist_t *llist);
int llist_destroy(d_llist_t *llist);
typedef int (*traver)(void *node);
int llist_traver(d_llist_t *llist, traver tvr);
int llist_check(d_llist_t *llist, compare cmp);
#endif
double_llist.c
#include <stdio.h>
#include <stdlib.h>
#include "./double_llist.h"
typedef struct llist_node_s{
void *key;
struct llist_node_s *prev;
struct llist_node_s *next;
}llist_node_t;
typedef struct llist_s{
llist_node_t *head;
llist_node_t *tail;
}llist_t;
int llist_init(void **llist){
llist_t *me = NULL;
me = (llist_t*)malloc(sizeof(*me));
if(me == NULL){
return -1;
}
me->head = NULL;
me->tail = NULL;
*llist = me;
return 0;
}
int llist_insert(d_llist_t *llist, void *key, compare cmp){
llist_t *me = llist;
llist_node_t *cur = me->head;
llist_node_t *node_ = NULL;
node_ = (llist_node_t*)malloc(sizeof(*node_));
if(node_ == NULL){
return -1;
}
node_->next = NULL;
node_->prev = NULL;
node_->key = key;
int res = 0;
while(cur != NULL){
res = cmp(key, cur->key);
if(res > 0){
cur = cur->next;
}else{
break;
}
}
if(cur == NULL){
node_->prev = me->tail;
node_->next = NULL;
if(me->tail != NULL){
me->tail->next = node_;
me->tail = node_;
}else{
me->tail = node_;
}
if(me->head == NULL){
me->head = node_;
}
}else if(cur == me->head){
node_->next = me->head;
node_->prev = NULL;
me->head->prev = node_;
me->head = node_;
}else{
node_->next = cur;
node_->prev = cur->prev;
cur->prev->next = node_;
cur->prev = node_;
}
return 0;
}
void *llist_pop_first(void *llist){
llist_t *me = llist;
llist_node_t *cur = me->head;
if(cur == NULL){
return NULL;
}else if(cur->next == NULL){
me->head = NULL;
me->tail = NULL;
}else{
me->head = cur->next;
me->head->prev = NULL;
}
void *ret = cur->key;
free(cur);
return ret;
}
void *llist_pop_last(void *llist){
llist_t *me = llist;
llist_node_t *cur = me->tail;
if(cur == NULL){
return NULL;
}else if(cur->prev == NULL){
me->head = NULL;
me->tail = NULL;
}else{
me->tail = cur->prev;
me->tail->next = NULL;
}
void *ret = cur->key;
free(cur);
return ret;
}
int llist_destroy(void *llist){
llist_t *me = llist;
llist_node_t *cur = me->head, *temp = NULL;
while(cur != NULL){
temp = cur->next;
free(cur->key);
free(cur);
cur = temp;
}
free(me);
llist = NULL;
return 0;
}
int llist_traver(void *llist, traver tvr){
llist_t *me = llist;
llist_node_t *cur = me->head;
while(cur != NULL){
tvr(cur->key);
cur = cur->next;
if(cur){
printf(" -> ");
}
}
printf("\n");
return 0;
}
int llist_check(void *llist, compare cmp){
llist_t *me = llist;
llist_node_t *cur = me->head;
if(cur != NULL && cur->next != NULL){
cur = cur->next;
}else{
return 0;
}
while(cur != NULL){
if(cmp(cur->key, cur->prev->key) < 0){
return -1;
}
cur = cur->next;
}
return 0;
}
d_llist_node_t *llist_head_look(d_llist_t *llist){
llist_t *me = llist;
if(me->head == NULL){
return NULL;
}
return me->head->key;
}
d_llist_node_t *llist_tail_look(d_llist_t *llist){
llist_t *me = llist;
if(me->tail == NULL){
return NULL;
}
return me->tail->key;
}
测试代码 test.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "./double_llist.h"
int mycompare(void *a, void *b){
int *x = a;
int *y = b;
return (*x) - (*y);
}
int mytraver(void *key){
int *x = key;
printf("[%d]", *x);
return 0;
}
int main(){
d_llist_t *llist = NULL;
int ret = 0;
ret = llist_init(&llist);
if(ret){
puts("init()");
exit(1);
}
srand((unsigned)time(NULL));
int i = 0;
for(i = 0; i < 1024 * 16; i++){
int *key = (int*)malloc(sizeof(int));
(*key) = (rand() % 1024 + 1);
ret = llist_insert(llist, key, mycompare);
if(i % 2){
llist_pop_last(llist);
}
}
ret = llist_check(llist, mycompare);
if(ret){
printf("error\n");
}else{
printf("ok\n");
}
int *data = llist_head_look(llist);
if(data != NULL){
mytraver(data);
}else{
printf("llist is empty\n");
}
data = NULL;
data = llist_tail_look(llist);
if(data != NULL){
mytraver(data);
}else{
printf("llist is empty\n");
}
ret = llist_destroy(llist);
if(ret){
puts("destroy()");
exit(1);
}
exit(0);
}
总结
功能列表
- 数据都是用户自己定义
- 链表的有序 / 无序插入,如何排序可以由用户自己控制
- 链表的首尾取出 / 查看
- 检测链表是否有序
- 链表的遍历, 打印格式也可以由用户自己设计,同时也可以打成日志
待添加功能
- 搜索查看 / 取出指定节点的 key;
- 可以在链表的结构体中添加一些额外的变量,用来记录链表中元素个数等等情况;\
- 更多的添加节点的方式,如头插法和尾插法;
- 等哪天用到的时候再总结.