注意:
1.封装函数,使用者不需要要了解底层细节,我们把内部使用的函数用static 声明.
2.我们存储的数据类型为void *, 由用户决定函数类型
3.代码尽可能减少代码量
#ifndef DLINK_H#define DLINK_H//用户应该只操作Dlink,避免操作节点.不需要了解细节struct _DLink;typedef struct _DLink DLink;DLink* dlist_create(void); // 创建链表void dlist_insert(DLink *link, int pos, void *data); //插入int dlist_delete(DLink *link,int pos);//删除void dlist_clean(DLink *link);//清空数据void dlist_destory(DLink *link);//销毁链表void print_char(int * dat); //打印一个字符方法void print_int(int * dat); //打印一个整形的方法void print(DLink *link, void( *v_print)(int *));//通用的打印方法,用来回调各种类型的数据的方法void dlist_foreach(DLink *link, void(*visit)(void *ctx, void *dat), void *ctx);//通用的递归方法,用来拓展#endif
1 //dlink.c 2 #include3 #include 4 #include "dlink.h" 5 6 //初始化头结点 7 static void dlist_init(DLink *link) 8 { 9 link->head = (DListNode*)malloc(sizeof(DListNode)); 10 if(link->head != NULL) 11 { 12 int data='q'; 13 int *dat =&data; 14 link->head->prior = NULL; 15 link->head->next = NULL; 16 17 link->head->dat =dat; 18 } 19 } 20 21 22 //创建一个双向链表 23 DLink* dlist_create(void) 24 { 25 DLink* link ; 26 if(link != NULL) 27 { 28 link->head = NULL; 29 dlist_init(link); 30 } 31 return link; 32 //函数不应该返回一个局部变量,栈内的数据极易丢失 33 //或者函数提供参数进来,该函数提供出事话,这样是可以的 34 } 35 36 37 //新建一个节点 38 static DListNode* dlist_node_create(void* data) 39 { 40 DListNode* node = malloc(sizeof(DListNode)); 41 if(node != NULL) 42 { 43 node->prior = NULL; 44 node->next = NULL; 45 node->dat = data; 46 } 47 return node; 48 } 49 50 //销毁一个节点 51 static void dlist_node_destroy(DListNode* node) 52 { 53 if(node != NULL) 54 { 55 node->next = NULL; 56 node->prior = NULL; 57 free(node); 58 } 59 return; 60 } 61 62 //插入链表 63 void dlist_insert(DLink *link, int pos, void *data) 64 { 65 int i=1; 66 DListNode *p = link->head; 67 DListNode *q = dlist_node_create(data); 68 DListNode *t; //用作记录尾节点 69 while(p) 70 { 71 if(pos==i) 72 { 73 q->next = p->next; 74 if(q->next!=NULL) //当只有头节点的时候插入一个节点会有问题,所以判断一下 75 q->next->prior = q; 76 q->prior = p; 77 p->next = q; 78 } 79 t = p; 80 p = p->next; 81 i++; 82 83 } 84 if(i prior = t; 87 q->next = t->next; 88 t->next = q; 89 90 } 91 92 } 93 94 void print_int(int * dat) 95 { 96 97 printf("%d ",*dat); 98 99 }100 101 void print_char(int * dat)102 {103 104 printf("%c ",*dat);105 106 }107 108 //通用的打印方法,需要传入一个函数,这里可以根据需求打印,就算实际类型不对,我们也可以按照需求打印处类型109 void print(DLink *link, void( *v_print)(int *))110 {111 DListNode *p =link->head->next;112 DListNode *q =p ; //一定要注意指针初始化,需要赋初值,否则可能会导致核心段错误,初值是个未知数,并不等于NULL113 printf("正序: ");114 while(p)115 {116 //我没有返回给主函数的回调函数.117 v_print(p->dat);118 q = p;119 p = p->next;120 }121 122 printf("\n逆序: ");123 while(q!=NULL &&q->prior!=NULL )124 {125 v_print(q->dat);126 q = q->prior;127 }128 printf("\n");129 }130 131 //遍历方法一个函数指针的形参 ,ctx为上下文,这个参数用来返回回调函数中计算的值,所以回调函数会对这个值进行操作132 void dlist_foreach(DLink *link, void(*visit)(void *ctx, void *dat), void *ctx)133 {134 DListNode *p =link->head->next;135 while(p)136 {137 //我就是传说中的回调函数.NB吧.138 visit(ctx,p->dat);139 p = p->next;140 }141 142 }143 144 //从链表中得到一个节点145 static DListNode* dlist_get_node(DLink* link,int index)146 {147 DListNode* p = link->head;148 149 while(p != NULL && p->next != NULL && index > 0)150 {151 p = p->next;152 index--;153 }154 if(index>0)155 {156 return NULL;157 }158 159 return p;160 }161 162 //删除一个节点163 int dlist_delete(DLink *link,int pos)164 {165 DListNode *p =dlist_get_node(link,pos);166 DListNode *q;167 if(p!=NULL)168 {169 q = p->prior;170 q->next = p->next;171 q->next->prior = q; 172 dlist_node_destroy(p); //删除节点173 return 0;174 }175 return -1;176 }177 178 //清空节点,但保留头结点179 void dlist_clean(DLink *link)180 {181 DListNode *p =link->head->next;182 DListNode *q;183 while(p)184 {185 q =p->next;186 dlist_node_destroy(p);187 p = q; 188 }189 link->head->next =NULL;190 }191 192 //销毁链表193 void dlist_destory(DLink *link)194 {195 dlist_clean(link);196 dlist_node_destroy(link->head);197 link->head =NULL;198 }
#include "dlink.h"//用户自定义函数,试试从不太那个的文件中的调用void max(int *ctx, int *dat){ if(*dat>*ctx) *ctx = *dat;}//得到值返回到ctx,所以这个值为上下文.void count(void *ctx, void *dat){ int *result = ctx; *result += *((int*)dat); return;}
//测试用的主函数
1 //main.c 2 #include "dlink.h" 3 #include4 5 extern void max(void *ctx, void *da); 6 extern void count(void *ctx, void *dat); 7 //经过实验,这里居然只要告诉编译器,我是一个函数就可以!!,形参只是写个程序员看的. 8 9 int main()10 {11 12 13 DLink *link=dlist_create();14 int c,m;15 int a[]={ 5,65,66,67,68,69,70,71,72};16 dlist_insert(link, 1, &a[1]);17 dlist_insert(link, 2, &a[2]);18 dlist_insert(link, 1, &a[0]);19 dlist_insert(link, 4, &a[4]);20 dlist_insert(link, 5, &a[5]);21 dlist_insert(link, 6, &a[6]);22 print(link,print_int); 23 dlist_foreach(link, count, &c);24 dlist_foreach(link, max, &m);25 printf("max=%d,count=%d\n",m,c);26 return 0;27 }