通用链表操作接口函数
2016-06-20 20:35
190 查看
list.c
/* * *通用链表操作函数定义 ** */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include "list.h" /*链表初始化*/ void list_init(List *list) { list->head = NULL; list->tail = NULL; list->len = 0; } /*是否为空链表*/ bool is_empty(List *list) { return (list->head == NULL); } /*创建链表*/ static struct node *make_node(void *data) //把用户传递过来的数据打包为一个链表节点 { struct node *n; n = malloc(sizeof(struct node)); assert(n != NULL); n->next = NULL; n->data = data; return n; } /*从链表的头节点插入新节点*/ void list_insert_at_head(List *list, void *data) //头插法 { struct node *n; n = make_node(data); if(list->head == NULL){ //如果是空链表 list->head = n; list->tail = n; } else{ //如果不是非空链表 n->next = list->head; list->head = n; } list->len++; } /*从链表的中部index节点插入节点*/ void list_insert_at_index(List *list, void *data, long index) { long i = 1; //从1开始算 struct node *p, *n; p = list->head; while(p && i < index){ p = p->next; i++; } if(p){ //如果链表遍历完了,计数i还没到index,说明第index个节点不存在。 n = make_node(data); n->next = p->next; p->next = n; list->len++; } } /*从链表的尾部节点插入新节点*/ void list_insert_at_tail(List *list, void *data) //尾插法 { struct node *n; n = make_node(data); if(is_empty(list)){ //如果是空链表 list->head = n; list->tail = n; } else{ //如果不是非空链表 list->tail->next = n; list->tail = n; } list->len++; } /* void list_insert(List *list, void *data) //默认采用尾插法 { #if 0 list_insert_at_tail(list, data); #else struct node *n; n = make_node(data); if(list->head == NULL){ list->head = n; list->tail = n; } else { list->tail->next = n; list->tail = n; } list->len++; #endif } */ /*从默认方式入新节点*/ void list_insert(List *list, void *data) { struct node *n; n = make_node(data); if(list->head == NULL){ list->head = n; list->tail = n; } else { list->tail->next = n; list->tail = n; } list->len++; } /*删除链表操作*/ void * list_delete(List *list, void *key, int (*compare)(const void *, const void *)) { void *data; struct node *n, *t; n = list->head; if(!compare(n->data, key)){ //如果要删除的节点为首节点 t = n; data = n->data; list->head = n->next; free(t); list->len--; return data; } while(n->next != NULL){ //遍历查找符合条件的节点,删除之 if(compare(n->next->data, key) == 0){ //只删除第一个符合条件的节点。 t = n->next; if(n->next == list->tail){ list->tail = n; } n->next = n->next->next; data = t->data; free(t); list->len--; return data; //把删除的数据返回给用户,供用户后续的处理使用。 } n = n->next; } return NULL; //没找到匹配的节点,返回NULL } /*搜索节点*/ void *list_search(List *list, void *key, int (*compare)(const void *, const void *)) { struct node *n; n = list->head; while(n){ if(!compare(n->data, key)){ //找到了,返回找到的数据 return n->data; } n = n->next; } return NULL; //找不到,返回NULL } static struct node *find_min_node(List *list, int (*compare)(const void *, const void *)) { struct node *min, *n; n = list->head; min = list->head; while(n){ if(compare(min->data, n->data) > 0){ min = n; } n = n->next; } return min; } //删除链表中的某个节点 static void delete_node(List *list, struct node *key) { struct node *n; n = list->head; if(n == key){ list->head = n->next; return; } while(n->next){ if(n->next == key){ if(key == list->tail){ list->tail = n; } n->next = n->next->next; return; } n = n->next; } } //插入节点 static void insert_node(List *list, struct node *key) { if(list->head == NULL){ list->head = key; list->tail = key; }else{ list->tail->next = key; list->tail = key; } } //节点遍历 void list_sort(List *list, int (*compare)(const void *, const void *)) { List tmp; struct node *n; list_init(&tmp); while(! is_empty(list)){ n = find_min_node(list, compare); delete_node(list, n); n->next = NULL; insert_node(&tmp, n); } list->head = tmp.head; list->tail = tmp.tail; } //链表遍历 void list_traverse(List *list, void (*handle)(void *)) { struct node *p; p = list->head; while(p){ handle(p->data); p = p->next; } } //链表翻转 void list_reverse(List *list) { struct node *pre = NULL, *next, *p = list->head; list->tail = list->head; //tail指向head; while(p){ next = p->next; if(!next){ //当p->next为最后一个节点时,让head指向p->next list->head = p; } //记录当前节点为pre,作为下一个节点的next.第一个节点为NULL,初始化时已定义。 p->next = pre; pre = p; p = next; } } //获取链表长度 long list_get_lenth(List *list) { return (list->len); } void *list_get_element(List *list, int idx) { int i = 1; struct node *n; n = list->head; while(n && i < idx){ i ++; n = n->next; } if(n){ return n->data; } return NULL; } //链表销毁 void list_destroy(List *list, void (*destroy)(void *)) { list->len = 0; struct node *n, *t; n = list->head; while(n){ t = n->next; //t只起一个记录n->next的功能,否则后面把n free掉之后,就找不到n->next了。 if(destroy){ //传递用户自定义的数据处理函数,为0时不执行 destroy(n->data); //使用用户提供的destroy函数来释放用户传递过来的数据。 } free(n); n = t; //把n free掉之后,再把t给n,相当于把n->next给n,如此循环遍历链表,挨个删除, } }
<span style="font-family: Arial, Helvetica, sans-serif;">main.c</span>
#include <stdio.h> #include "list.h" //测试数据结构 typedef struct test{ int val1; float val2; }test_t; //显示(打印)链表数据 void handle(void *data) { test_t *test = (test_t *)data; printf("val1:%d, val2:%f\n", test->val1, test->val2); } //比较两个数据的大小 int compare_int(const void *s1, const void *s2) { test_t *data1 = (test_t *)s1; int *data2 =(int *)s2; return (data1->val1 - *data2); } //排序比较大小 int compare_int_sort(const void *s1, const void *s2) { test_t *data1 = (test_t *)s1; test_t *data2 = (test_t *)s2; return (data1->val1 - data2->val1); } //打印链表 void print(List *list) { printf("list len = %ld\n", list_get_lenth(list)); if(!is_empty(list)){ //test list_reverse list_traverse(list, handle); } else{ printf("\tthe list is empty\n"); } } int main(void) { //实例化List链表 List list; //初始化链表 list_init(&list); //测试数据test_t定义 test_t test1 = {10, 10.5}; <span style="white-space:pre"> </span>test_t test2 = {20, 20.5}; <span style="white-space:pre"> </span>test_t test3 = {30, 30.5}; <span style="white-space:pre"> </span>test_t test4 = {40, 40.5}; <span style="white-space:pre"> </span>test_t test5 = {50, 50.5}; //默认从尾部插入tail //test list_insert printf("------insert(_at_tail)----\n"); list_insert(&list, &test1);//10 10.5 list_insert(&list, &test2);//20 20.5 list_insert(&list, &test3);//30 30.5 print(&list); //删除 //test list_delete printf("------delete----\n"); list_delete(&list, &test1.val1, compare_int);//函数指针compare_init print(&list); //test list_insert_at_head printf("------insert_at_head----\n"); list_insert_at_head(&list, &test4); print(&list); //test list_insert_at_index printf("------insert_at_index(2)----\n"); list_insert_at_index(&list, &test5, 2); print(&list); //test list_reverse printf("------reverse----\n"); list_reverse(&list); print(&list); //test list_search int key = 20; test_t *ret; printf("------search----\n"); ret = list_search(&list, &key, compare_int); printf("%d:%f\n", ret->val1, ret->val2); key = 50; ret = list_search(&list, &key, compare_int); printf("%d:%f\n", ret->val1, ret->val2); //test list_get_element printf("------list_get_element----\n"); ret = list_get_element(&list, 2); printf("%d:%f\n", ret->val1, ret->val2); ret = list_get_element(&list, 3); printf("%d:%f\n", ret->val1, ret->val2); //test list_sort printf("-----sort----\n"); list_sort(&list, compare_int_sort); print(&list); <span style="white-space:pre"> </span>//test if list is empty\n <span style="white-space:pre"> </span>printf("-----check is_empty------"); <span style="white-space:pre"> </span>if(!is_empty(&list)) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>printf("list is not empty\n"); <span style="white-space:pre"> </span>printf("list len = %ld\n", list_get_lenth(&list)); <span style="white-space:pre"> </span>} //test list_destroy printf("-----destroy----\n"); list_destroy(&list, NULL); <span style="white-space:pre"> </span>//test is_empty <span style="white-space:pre"> </span>printf("-----is_empty------"); <span style="white-space:pre"> </span>if(!is_empty(&list)) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>printf("list is not empty\n"); <span style="white-space:pre"> </span>printf("list len = %ld\n", list_get_lenth(&list)); <span style="white-space:pre"> </span>} return 0; }
相关文章推荐
- 运算符重载的函数(3)
- c高级字长字节序对齐
- sql查询优化 索引优化
- c高级c存储类型
- 【剑指offer】(扩展)求链表中间结点
- 【设计模式】备忘录模式
- select from table where 1=1
- 第十六周上机实践项目4(3):程序设计
- 爱因斯坦的题目C语言解法(老贴)
- 不同厂家的电脑进入bios的快捷键整理汇总
- 第127课: Spark Streaming源码经典解读系列之二:Spark Streaming生成RDD
- 性能测试——造数
- 键盘遮挡———视图随键盘移动
- C# II: Class ViewModelBase and RelayCommand in MVVM
- 异常解决:A master URL must be set in your configuration
- 委托
- 《构建之法》第六章
- 安卓应用实时显示MJGP-streamer所抓取的摄像头信息
- 静态库改为动态库后,可以影响到程序的执行结果
- ajax无刷新上传