概述
本文作为《也没想象中那么神秘的数据结构-一种通用化双向链表设计》系列最后一篇,主要用于验证底层源码和对象设计的源码正确性,另外也向用户展示通用链表类的使用方法。
示例
★结合《也没想象中那么神秘的数据结构-一种通用化双向链表设计(底层源码)》和《也没想象中那么神秘的数据结构-一种通用化双向链表设计(对象设计)》中的源码使用。
★调用通用链表类创建整型链表对象(节点元素数据类型为整型)和字符串型链表对象(节点元素数据类型为字符串类型)。
★调用方法完成插入、删除、查找等相关操作。
★包含源文件dll_app.c(已验证通过)。
dll_app.c
/** * @Filename : dll_app.c * @Revision : $Revision: 1.0 $ * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅) * @Description : 通用双向链表测试应用代码 **/ #include "dll.h" #include "class_dll.h" /* 类操作, 带参数 */ #define CLASS_CALL(THIS,func,args...) ((THIS)->func(THIS,args)) /* 类操作, 无参数 */ #define CLASS_CALL_0(THIS,func) ((THIS)->func(THIS)) /* 元素节点定义,存放整型数据 */ struct t_int_node{ struct t_node node; /* 节点元素指针 */ int id; /* 节点元素值 */ }; /* 判断节点中是否包含指定信息 */ int cmp_int_key(struct t_node *node, void *key) { struct t_int_node *p_node = NULL; if ((node == NULL) || (key == NULL)) return -1; p_node = (struct t_int_node *)node; return (p_node->id == *(int *)key ? 0 : -1); } /* 打印节点信息 */ void print_int_node(struct t_node *node) { struct t_int_node *p_node = NULL; if (node == NULL) return; p_node = (struct t_int_node *)node; printf("%d ", p_node->id); } /* 整型链表测试,节点存放数据类型为整型 */ void int_test(void) { int i; struct t_int_node *p_node = NULL; struct dll *p_dll = new_dll(cmp_int_key, print_int_node); if (p_dll == NULL) return; printf("*****integer list test*****\n"); printf("list: "); /* 插入7个元素到链表, 链表:0 1 2 3 4 5 6 */ for (i=0; i<7; i++) { if ((p_node = (struct t_int_node *)malloc(sizeof(struct t_int_node))) != NULL) { p_node->id = i; CLASS_CALL(p_dll, add, (struct t_node *)p_node); } } CLASS_CALL_0(p_dll, show); printf("---------------------------\n"); /* 最后一个元素为6, 第四个元素为3,一共7个元素 */ p_node = (struct t_int_node *)CLASS_CALL_0(p_dll, get_last); printf("last node is %d\n", p_node->id); p_node = (struct t_int_node *)CLASS_CALL(p_dll, get_n_th, 4); printf("4th node is %d\n", p_node->id); printf("list count is %d\n", CLASS_CALL_0(p_dll, get_count)); printf("---------------------------\n"); /* 删除第2元素1和元素值为5的元素,此时链表:0 2 3 4 6,第四个元素为4,一共5个元素 */ CLASS_CALL(p_dll, del_n_th, 2); i = 5; CLASS_CALL(p_dll, del_key, &i); CLASS_CALL_0(p_dll, show); p_node = (struct t_int_node *)CLASS_CALL(p_dll, get_n_th, 4); printf("4th node is %d\n", p_node->id); printf("list count is %d\n", CLASS_CALL_0(p_dll, get_count)); printf("\n"); } /* 元素节点定义,存放字符串数据 */ struct t_str_node{ struct t_node node; /* 节点元素指针 */ char name[16]; /* 节点元素值 */ }; /* 判断节点中是否包含指定信息 */ int cmp_str_key(struct t_node *node, void *key) { struct t_str_node *p_node = NULL; if ((node == NULL) || (key == NULL)) return -1; p_node = (struct t_str_node *)node; return (strcmp(p_node->name, (char *)key)); } /* 打印节点信息 */ void print_str_node(struct t_node *node) { struct t_str_node *p_node = NULL; if (node == NULL) return; p_node = (struct t_str_node *)node; printf("%s ", p_node->name); } /* 字符串型链表测试,节点存放数据类型为字符串型 */ void str_test(void) { int i; struct t_str_node *p_node = NULL; struct dll *p_dll = new_dll(cmp_str_key, print_str_node); if (p_dll == NULL) return; printf("*****string list test*****\n"); printf("list: "); /* 插入7个元素到链表, 链表:n0 n1 n2 n3 n4 n5 n6 */ for (i=0; i<7; i++) { if ((p_node = (struct t_str_node *)malloc(sizeof(struct t_str_node))) != NULL) { sprintf(p_node->name, "n%d", i); p_dll->add(p_dll, (struct t_node *)p_node); } } CLASS_CALL_0(p_dll, show); /* 最后一个元素为n6, 第四个元素为n3,一共7个元素 */ p_node = (struct t_str_node *)p_dll->get_last(p_dll); printf("last node is %s\n", p_node->name); p_node = (struct t_str_node *)p_dll->get_n_th(p_dll, 4); printf("4th node is %s\n", p_node->name); printf("list count is %d\n", p_dll->get_count(p_dll)); printf("---------------------------\n"); /* 删除第2元素n1和元素值为name5的元素(不存在,删除失败),此时链表:n0 n2 n3 n4 n5 n6,第四个元素为n4,一共6个元素 */ p_dll->del_n_th(p_dll, 2); p_dll->del_key(p_dll, "name5"); p_dll->show(p_dll); p_node = (struct t_str_node *)p_dll->get_n_th(p_dll, 4); printf("4th node is %s\n", p_node->name); printf("list count is %d\n", p_dll->get_count(p_dll)); } int main(void) { int_test(); str_test(); return 0; }
结论
feng@feng-vm:~/share/dll$ gcc -o dll_test dll_app.c class_dll.c dll.c feng@feng-vm:~/share/dll$ ./dll_test *****integer list test***** list: 0 1 2 3 4 5 6 --------------------------- last node is 6 4th node is 3 list count is 7 --------------------------- 0 2 3 4 6 4th node is 4 list count is 5 *****string list test***** list: n0 n1 n2 n3 n4 n5 n6 last node is n6 4th node is n3 list count is 7 --------------------------- n0 n2 n3 n4 n5 n6 4th node is n4 list count is 6 feng@feng-vm:~/share/dll$
分析:
1. 示例在int_test()函数中调用通用链表对象类创建整型链表对象,并对链表进行元素插入、删除、查找操作。
2. 示例在str_test()函数中调用通用链表对象类创建字符串型链表对象,并对链表进行元素插入、删除、查找操作。
3. 由上示例可以看出,对于链表的操作,与节点数据类型构成并无太大的关系,只是在一些对数据需要进行特殊处理的时候才会有所区分,例如查找指定信息、输出数据信息等,此时我们可以采用模版模式,将差异化的接口抽象出来,通过子类进行实现,从而做到通用化的目的。
往期 · 推荐
也没想象中那么神秘的数据结构-一种通用化的双向链表设计(底层源码)
关注
更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:数据结构源码,也可点击此处下载。