4.数据结构之通用链表实现
来源:互联网 发布:java输出99乘法表 编辑:程序博客网 时间:2024/05/01 08:34
数据结构之通用链表实现
通用链表简介
在redis数据库和acl库中,通用双端链表的应用随处可见。之前我们接触过链表的相关操作,前两章:《数据结构之单链表》以及《数据结构之链表面试题》接触了不少链表的问题,但是对于问题的处理总是无法逃脱类型的限定,所以我们需要将类型的问题从数据结构中剥离出来。具体的类型在数据结构的使用者进行具体的限定。好吧,我们首先来看看头文件dlist.h中关于链表节点结构的定义和接口的声明:
//防止头文件的内容被重复包含#ifndef _DLIST_H_#define _DLIST_H_#include <stdio.h>#include <stdlib.h>#include <strings.h>#define ZERO (0)#define ONLY_ONE (1)#define TRUE (1)#define FALSE (0)struct Dlist;typedef struct Dlist Dlist; //双端链表控制信息struct Dlist_node;typedef struct Dlist_node Dlist_node; //双短链表节点信息typedef unsigned char Boolean; //C语言中的布尔值//链表控制信息struct Dlist{ struct Dlist_node *head; //指向双端链表的头节点 struct Dlist_node *tail; //指向双端链表的尾节点 int count; //双端链表中的元素个数 //释放链表节点数据域 void (*free)(void *ptr); //void (*)(void *ptr) free; //匹配链表节点数据域 Boolean (*match)(void *val1, void *val2); //拷贝链表节点数据域 void *(*copy_node)(void *src);};//链表节点信息struct Dlist_node{ struct Dlist_node *prev; //前一个节点指针 struct Dlist_node *next; //后一个节点指针 void *data; //数据(指针)};typedef void (*Print_func)(void *value);//双端链表的接口(ADT)Dlist *init_dlist(void) ; //链表的初始化void destroy_dlist(Dlist **dlist) ; //链表的销毁Boolean push_front(Dlist *dlist, void *value); //链表头部插入Boolean push_back(Dlist *dlist, void *value) ; //链表尾部插入Boolean pop_back(Dlist *dlist) ; //链表尾部删除Boolean pop_front(Dlist *dlist) ; //链表头部删除Boolean insert_prev_node(Dlist *dlist, Dlist_node *node, void *value) ; //插入指定节点的前边Boolean insert_next_node(Dlist *dlist, Dlist_node *node, void *value) ; //插入指定节点的后边Boolean remove_dlist_node(Dlist *dlist, Dlist_node *node, void **value) ; //删除链表中的节点 void print_dlist(Dlist *dlist, Print_func print) ; //打印双端链表Dlist_node *get_index_node(Dlist *dlist, int index) ; //得到下标为index的链表元素Boolean get_front(Dlist *dlist, void **value) ; //得到链表头节点的数据域Boolean get_tail(Dlist *dlist, void **value) ; //得到链表尾节点的数据域int get_dlist_count(Dlist *dlist) ; //得到链表元素个数//void print_int(void *value); //打印整形值#endif
在参数传递中我们对于数据的传递都是采用的指针的传递,并且都是void *类型,这样就可以接受任意类型的数据。在结构上我们依然设计了链表控制信息和链表节点信息两部分,这里我们使用了函数指针的技术,函数指针可以让该指针指向相同类型的函数(返回值和参数列表相同)。首先我们得定义出函数指针的这种类型:
typedef void (*Print_func)(void *value);
这就是说Print_func是一种类型,这种类型可以定义相关指针,该指针可以指向型如
void func1(void *value)类型的函数。
关于链表接口的实现我们在dlist.c中进行实现,代码如下所示:
#include "dlist.h"#include "tools.h"void destroy_dlist(Dlist **dlist) //链表的销毁{ Dlist_node *p_node = NULL; if(dlist == NULL || *dlist == NULL){ return ; } p_node = (*dlist)->head; while((*dlist)->head != NULL){ (*dlist)->head = p_node->next; if((*dlist)->free != NULL){ (*dlist)->free(p_node->data); } free(p_node); p_node = (*dlist)->head; } free(*dlist); *dlist = NULL;}static Dlist_node *buy_node(void){ Dlist_node *result = (Dlist_node *)Malloc(sizeof(Dlist_node)); bzero(result, sizeof(Dlist_node)); return result;}Boolean push_front(Dlist *dlist, void *value) //链表头部插入{ Dlist_node *node = NULL; if(dlist == NULL || value == NULL){ return FALSE; } node = buy_node(); node->data = value; if(dlist->count == ZERO){ //链表没有元素时 dlist->head = dlist->tail = node; }else{ node->next = dlist->head; dlist->head->prev = node; dlist->head = node; } dlist->count++; return TRUE;}Boolean push_back(Dlist *dlist, void *value) //链表尾部插入{ Dlist_node *node = NULL; if(dlist == NULL || value == NULL){ return FALSE; } node = buy_node(); node->data =value; if(dlist->count == ZERO){ dlist->head = dlist->tail = node; }else{ node->prev = dlist->tail; dlist->tail->next = node; dlist->tail = node; } dlist->count++; return TRUE;}Boolean pop_back(Dlist *dlist) //链表尾部删除{ Dlist_node *p_node = NULL; if(dlist == NULL || dlist->count == ZERO){ return FALSE; } p_node = dlist->tail; if(dlist->count == ONLY_ONE){ dlist->head = dlist->tail = NULL; }else{ dlist->tail = p_node->prev; dlist->tail->next = NULL; } if(dlist->free != NULL){ dlist->free(p_node->data); } free(p_node); dlist->count--; return TRUE;}Boolean pop_front(Dlist *dlist) //链表头部删除{ Dlist_node *p_node = NULL; if(dlist == NULL || dlist->count == ZERO){ return FALSE; } p_node = dlist->head; if(dlist->count == ONLY_ONE){ dlist->head = dlist->tail = NULL; }else{ dlist->head = p_node->next; dlist->head->prev = NULL; } if(dlist->free != NULL){ dlist->free(p_node->data); } free(p_node); dlist->count--; return TRUE;}Dlist_node *get_index_node(Dlist *dlist, int index) //得到下标为index的链表节点{ Dlist_node *node = NULL; int move_count = 0; if(dlist == NULL || dlist->count == ZERO || index < ZERO || index >= dlist->count){ return NULL; } node = dlist->head; move_count = index; //找到指定下标元素 while(move_count--){ node = node->next; } return node;}Boolean remove_dlist_node(Dlist *dlist, Dlist_node *node, void **value) //删除指定节点{ if(dlist == NULL || node == NULL){ return FALSE; } if(value != NULL){ //取得被删除节点数据域信息 *value = node->data; } if(node->next == NULL){ //node在尾部 pop_back(dlist); }else if(node->prev == NULL){ pop_front(dlist); }else{ node->prev->next = node->next; node->next->prev = node->prev; if(dlist->free != NULL){ dlist->free(node->data); } free(node); //Free(node) dlist->count--; /* * * #define Free(node) (node->prev->next = node->next;) \ * (node->next->prev = node->prev;) \ * * * */ } return TRUE;}Boolean insert_next_node(Dlist *dlist, Dlist_node *node, void *value) //插入到指定节点的后边{ Dlist_node *p_node = NULL; if(dlist == NULL || node == NULL || value){ return FALSE; } p_node = buy_node(); p_node->data = value; p_node->prev = node; p_node->next = node->next; if(node->next == NULL){ dlist->tail = p_node; }else{ node->next->prev = p_node; } node->next = p_node; dlist->count++; return TRUE;}Boolean insert_prev_node(Dlist *dlist, Dlist_node *node, void *value) //插入到指定节点的前边{ Dlist_node *p_node = NULL; if(dlist == NULL || node == NULL || value == NULL){ return FALSE; } p_node = buy_node(); p_node->data = value; //进行插入操作 p_node->next = node; p_node->prev = node->prev; if(node->prev == NULL){ //node为第一个节点 dlist->head = p_node; }else{ //node不是第一个节点 node->prev->next = p_node; } node->prev = p_node; dlist->count++; return TRUE;}void print_int(void *value){ printf("%d ", *(int *)value);}void print_dlist(Dlist *dlist, Print_func print) //打印链表信息{ Dlist_node *p_node = NULL; if(dlist == NULL || dlist->count == ZERO){ return ; } for(p_node = dlist->head; p_node ; p_node = p_node->next){ print(p_node->data); } printf("\n");}Dlist *init_dlist(void) //双端链表的初始化{ Dlist *dlist = NULL; dlist = (Dlist *)Malloc(sizeof(Dlist)); bzero(dlist, sizeof(Dlist)); //对dlist进行初始化 return dlist;}Boolean get_front(Dlist *dlist, void **value){ if(dlist == NULL || dlist->count == ZERO){ return FALSE; } if(value != NULL){ *value = dlist->head->data; } return TRUE;}Boolean get_tail(Dlist *dlist, void **value){ if(dlist == NULL || dlist->count == ZERO){ return FALSE; } if(value != NULL){ *value = dlist->tail->data; } return TRUE;}int get_dlist_count(Dlist *dlist){ if(dlist == NULL){ return -1; } return dlist->count;}
在dlist.c文件中我们包含了一个tools.h,这个是我们的工具类文件,其中包含了对内存和简单算法的相关接口,分为tools.h和tools.c两个文件:
#ifndef _TOOLS_H_#define _TOOLS_H_#include <stdio.h>#include <stdlib.h>#include <string.h>void *Malloc(size_t size); //申请堆空间void swap(void *a, void *b, int length); //交换任意两个值#endif
对应的tools.c文件:
#include "tools.h"void *Malloc(size_t size){ void *result = malloc(size); if(result == NULL){ fprintf(stderr, "the memory is full!\n"); exit(1); } return result;}void swap(void *a, void *b, int length){ void *temp = malloc(length); memcpy(temp, a, length); memcpy(a, b, length); memcpy(b, temp, length); free(temp);}
关于通用链表的测试代码入下所示:
//通用链表测试代码#include <stdio.h>#include "dlist.h"int main(int argc, char **argv){ Dlist *dlist1 = NULL; int array[] = {12, 23, 34, 4, 1, 33, 24}; int array1[] = {1, 33, 44, 2, 33, 222, 444}; int arr_len = sizeof(array) / sizeof(array[0]); int i = 0; dlist1 = init_dlist(); //双端链表的初始化 //初始化完成后,如果有需要,应修改free、match和dup的指向 for(i = 0; i < arr_len; ++i){ push_back(dlist1, &array[i]); } print_dlist(dlist1, print_int); pop_back(dlist1); push_front(dlist1, &array1[2]); print_dlist(dlist1, print_int); destroy_dlist(&dlist1); //双端链表的销毁 return 0;}
通用链表在redis数据库中具有着非常多的应用:
可以作为底层容器的实现,用来改造,添加保存节点长度的字段。或者说python的基本数据类型列表、元组的底层容器。以及后期我们将要使用适配器模式对通用双端链表进行封装,创建出栈和队列。
敬请期待!
1 0
- 4.数据结构之通用链表实现
- 6.数据结构之通用栈(链表实现)
- 数据结构之双端(通用)链表的实现
- c语言实现通用数据结构(一):通用链表
- c语言实现通用数据结构(一):通用链表
- C实现通用数据结构--双向链表
- 数据结构通用双向循环链表实现
- c语言数据结构之通用链表
- 数据结构之通用树(使用链表实现树的存储结构,双亲孩子表示法)
- 数据结构之通用双端链表
- 数据结构之通用树
- 数据结构之通用树
- 数据结构之链表实现
- C++中实现通用数据结构
- Java 数据结构之通用菜单
- 数据结构之双向链表的实现
- 数据结构之单向链表实现
- 数据结构之双向链表实现
- Hi3531第一次调试 遇到的问题。
- Android定位入门(3),基础实战部分
- 计算机图形学 4.1.4 三维旋转 4.2.1 正投影(三视图)
- Java核心技术第12章(2)
- null在不同的语言中标识方法
- 4.数据结构之通用链表实现
- 关于问题的分析小结(1)-----bzoj1016最小生成树计数
- Eclipse常用快捷键
- HDU - 1542 Atlantis(线段树 扫描线)
- git服务端安装及配置
- LeetCode(125) Valid Palindrome
- 开发该选择Blocks还是Delegates
- 信号发送函数(2)
- java代码规范