内容简介:通过对《Redis设计与实现》一书的学习,我打算动手自己实现一份“Redis源代码”作为自己的学习记录。对Redis感兴趣的同学可以查看我的另一篇文章本章介绍的是Redis源代码中的双端链表list的实现。
通过对《Redis设计与实现》一书的学习,我打算动手自己实现一份“Redis源代码”作为自己的学习记录。
对 Redis 感兴趣的同学可以查看我的另一篇文章 造个轮子 | 自己动手写一个Redis 。
本章介绍的是Redis源代码中的双端链表list的实现。
双端链表list的实现
list的API
(1)创建一个不包含任何结点的新链表
list *listCreate(void);
(2)释放给定链表,以及链表中的所有结点
void listRelease(list *l);
(3)将一个包含给定值的新节点添加到给定链表的表头
list listAddNodeHead(list l, void *value);
(4)将一个包含给定值的新节点添加到给定链表的表尾
list listAddNodeTail(list l, void *value);
(5)将一个包含给定值的新节点添加到给定结点的之前或之后
list listInsertNode(list l, listNode old_node, void value, int after);
(6)从链表中删除给定结点
list listDelNode(list l, listNode *node);
(7)复制一个给定链表的副本
list listDup(list orig);
(8)查找并返回链表中包含给定值的结点
listNode listSearchKey(list l, void *key);
(9)返回链表在给定索引上的结点
listNode listIndex(list l, long index);
(10)将链表结点的表位结点弹出,然后将被弹出的结点插入到链表的表头,成为新的表头结点
void listRotate(list *l);
头文件
#ifndef __ADLIST_H__ #define __ADLIST_H__ //双端链表 //双端链表的结点 typedef struct listNode{ struct listNode *prev;//指向点一个结点的指针 struct listNode *next;//指向下一个结点的指针 void *value;//结点存放的值 }listNode; //链表 typedef struct list{ listNode *head;//头结点 listNode *tail;//尾结点 int len;//链表的长度 //用于实现多态链表所需的类型的特定函数 //函数指针 //用于复制链表结点所保存的值 void *(*dup)(void *ptr); //用于释放链表结点所保存的值 void (*free)(void *ptr); //用于对比 int (*match)(void *ptr, void *key); }list; //定义对链表进行操作的宏 //获取链表长度 #define listLength(l) ((l)->len) //获取链表的头结点 #define listFirst(l) ((l)->head) //获取链表的尾结点 #define listLast(l) ((l)->tail) //获取前一个结点 #define listPrevNode(n) ((n)->prev) //获取下一个结点 #define listNextNode(n) ((n)->next) //获取该结点的值 #define listNodeValue(n) ((n)->value) //设置复制操作的函数指针 #define listSetDupMethod(l,m) ((l)->dup = (m)) //设置释放操作的函数指针 #define listSetFreeMethod(l,m) ((l)->free = (m)) //设置对比操作的函数指针 #define listSetMatchMethod(l,m) ((l)->match = (m)) //获取复制链表结点的函数指针 #define listGetDupMethod(l) ((l)->dup) //获取释放链表结点的函数指针 #define listGetFree(l) ((l)->free) //获取比较链表结点的函数指针 #define listGetMatchMethod(l) ((l)->match) //创建一个不包含任何结点的新链表 list *listCreate(void); //释放给定链表,以及链表中的所有结点 void listRelease(list *l); //将一个包含给定值的新节点添加到给定链表的表头 list *listAddNodeHead(list *l, void *value); //将一个包含给定值的新节点添加到给定链表的表尾 list *listAddNodeTail(list *l, void *value); //将一个包含给定值的新节点添加到给定结点的之前或之后 list *listInsertNode(list *l, listNode *old_node, void *value, int after); //从链表中删除给定结点 list *listDelNode(list *l, listNode *node); //复制一个给定链表的副本 list *listDup(list *orig); //查找并返回链表中包含给定值的结点 listNode *listSearchKey(list *l, void *key); //返回链表在给定索引上的结点 listNode *listIndex(list *l, long index); //将链表结点的表位结点弹出,然后将被弹出的结点插 //入到链表的表头,成为新的表头结点 void listRotate(list *l); #endif
list API的实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "adlist.h" //创建一个不包含任何结点的新链表 list *listCreate(void){ list* l=(list*)malloc(sizeof(list)); //没有结点 l->head=NULL; l->tail=NULL; l->len=0; l->dup=NULL; l->free=NULL; l->match=NULL; return l; } //释放给定链表,以及链表中的所有结点 void listRelease(list *l){ if(l==NULL){ return ; } //没有head(没有结点) if(l->head==NULL){ return ; } //保证了链表是有结点存在的 //用来移动的指针,指向第一个结点 listNode*temp=l->head; while(temp->next!=NULL){ temp=temp->next; //使用链表对应释放value的free来释放value的值 if(l->free!=NULL){ l->free(temp->value); }else{ printf("PIG Redis WARNING : List->free is not define.\n"); } free(temp->prev); } free(temp); l->head=NULL; l->tail=NULL; free(l); l=NULL; return; } //将一个包含给定值的新节点添加到给定链表的表头 list *listAddNodeHead(list *l, void *value){ if(l==NULL){ printf("PIG Redis ERROR : List NULL.\n"); return NULL; } //链表中没有结点 if(l->head==NULL){ l->head=(listNode*)malloc(sizeof(listNode)); l->head->next=NULL; l->head->prev=NULL; //使用链表对应复制value的dup来复制value的值 if(l->dup!=NULL){ l->head->value=l->dup(value); }else{ printf("PIG Redis WARNING : List->dup is not define.\n"); l->head->value=value; } /* int *c=(int*)(l->head->value); printf("%d====\n",*c);*/ l->len=1; //头尾指针都指向新的结点 l->tail=l->head; return l; }else{ listNode*newone=(listNode*)malloc(sizeof(listNode)); //newone->value=value; //使用链表对应复制value的dup来复制value的值 if(l->dup!=NULL){ newone->value=l->dup(value); }else{ printf("PIG Redis WARNING : List->dup is not define.\n"); newone->value=value; } /* int *cc=(int*)(newone->value); printf("%d====\n",*cc);*/ newone->next=l->head; l->head->prev=newone; //新节点设为头结点 l->head=newone; newone->prev=NULL; l->len++; return l; } } //将一个包含给定值的新节点添加到给定链表的表尾 list *listAddNodeTail(list *l, void *value){ if(l==NULL){ printf("PIG Redis ERROR : List NULL.\n"); return NULL; } //链表中没有结点 if(l->head==NULL){ l->head=(listNode*)malloc(sizeof(listNode)); //l->head->value=value; //使用链表对应复制value的dup来复制value的值 if(l->dup!=NULL){ l->head->value=l->dup(value); }else{ printf("PIG Redis WARNING : List->dup is not define.\n"); l->head->value=value; } l->head->next=NULL; l->head->prev=NULL; l->tail=l->head; l->len=1; return l; }else{ listNode*temp=(listNode*)malloc(sizeof(listNode)); //temp->value=value; //使用链表对应复制value的dup来复制value的值 if(l->dup!=NULL){ temp->value=l->dup(value); }else{ printf("PIG Redis WARNING : List->dup is not define.\n"); temp->value=value; } temp->next=NULL; temp->prev=l->tail; l->tail->next=temp; l->tail=temp; l->len++; return l; } } //将一个包含给定值的新节点添加到给定结点的之前或之后 //after为1表示之后,after为0表示之前 list *listInsertNode(list *l, listNode *old_node, void *value, int after){ listNode *newone=(listNode*)malloc(sizeof(listNode)); //newone->value=value; //使用链表对应复制value的dup来复制value的值 if(l->dup!=NULL){ newone->value=l->dup(value); }else{ printf("PIG Redis WARNING : List->dup is not define.\n"); newone->value=value; } l->len++; if(after){ newone->next=old_node->next; newone->prev=old_node; old_node->next->prev=newone; old_node->next=newone; //检查原来的temp是否为tail if(l->tail==old_node){ l->tail=newone; } return l; }else{ newone->next=old_node; newone->prev=old_node->prev; old_node->prev->next=newone; old_node->prev=newone; //检查原来的temp是否为头结点 if(l->head==old_node){ l->head=newone; } return l; } } //从链表中删除给定结点 list *listDelNode(list *l, listNode *node){ l->len--; //使用链表对应释放value的free来释放value的值 if(l->free!=NULL){ l->free(node->value); }else{ printf("PIG Redis WARNING : List->free is not define.\n"); } //要删除的是最后一个结点 if(l->head==node&&l->tail==node){ free(node); l->head=NULL; l->tail=NULL; return l; }else if(l->head==node){ printf("head\n"); l->head=node->next; l->head->prev=NULL; free(node); return l; }else if(l->tail==node){ l->tail=node->prev; l->tail->next=NULL; free(node); return l; } node->prev->next=node->next; node->next->prev=node->prev; free(node); return l; } //复制一个给定链表的副本 list *listDup(list *orig){ if(orig==NULL){ return NULL; } //该链表没有结点 if(orig->head==NULL){ list*l=listCreate(); return l; }else{ list*l=listCreate(); listNode*temp=orig->head; while(temp!=NULL){ //向表尾插入 l=listAddNodeTail(l,temp->value); temp=temp->next; } return l; } } //查找并返回链表中包含给定值的结点 listNode *listSearchKey(list *l, void *key){ if(l==NULL){ printf("PIG Redis ERROR : List NULL.\n"); return NULL; //链表中没有结点 }else if(l->head==NULL){ printf("PIG Redis ERROR : List does't have nodes.\n"); return NULL; }else{ listNode*temp=l->head; //检查是否定义了比较value的函数 if(l->match==NULL){ printf("PIG Redis ERROR : List->match is not define.\n"); return NULL; } //match函数当两者相等时返回1 while(temp!=NULL&&!(l->match(key,temp->value))){ temp=temp->next; } if(temp==NULL){ printf("PIG Redis ERROR : List doesn't have this node.\n"); return NULL; }else{ return temp; } } } //返回链表在给定索引上的结点,index从0开始 listNode *listIndex(list *l, long index){ if(l==NULL){ printf("PIG Redis ERROR : List NULL.\n"); return NULL; }else if(l->head==NULL){ printf("PIG Redis ERROR : List doesn't have node.\n"); return NULL; } listNode*temp=l->head; for(int i=0;i<index&&temp!=NULL;i++){ temp=temp->next; } if(temp==NULL){ printf("PIG Redis ERROR : Subscript out of range.\n"); return NULL; } return temp; } //将链表结点的表尾结点弹出,然后将被弹出的结点插 //入到链表的表头,成为新的表头结点 void listRotate(list *l){ if(l==NULL){ printf("PIG Redis ERROR : List NULL.\n"); return ; }else if(l->head==NULL){ printf("PIG Redis ERROR : List doesn't have node.\n"); return ; }else if(l->head==l->tail){ printf("PIG Redis ERROR : List only have one node.\n"); return ; } listNode*node=l->tail->prev; l->tail->prev->next=NULL; l->tail->next=l->head; l->head->prev=l->tail; l->head=l->tail; l->tail=node; l->head->prev=NULL; } int intMatch(void *ptr, void *key){ int *a=(int *)ptr; int *b=(int *)key; return (*a==*b)?1:0; } void *intDup(void *ptr){ return ptr; } int main(){ printf("listCreate()\n"); list*l=listCreate(); printf("%d\n",l->len); listSetDupMethod(l,&intDup); int b=111; int *a=&b; l=listAddNodeHead(l,a); printf("%d\n",l->len); //使用void*指针的时候需要强制转换 int *c=(int *)(l->head->value); printf("%d\n",*c); int bb=12; int *aa=&bb; l=listAddNodeHead(l,aa); //listInsertNode(l,l->head,a,1); //l=listAddNodeTail(l,aa); //printf("%d\n",l->len); //l=listDelNode(l,l->head); //l=listDelNode(l,l->tail); //printf("%d\n",l->len); listRotate(l); //使用void*指针的时候需要强制转换 int *cc=NULL; listNode*temp=l->tail; while(temp){ cc=(int *)(temp->value); printf("%d\n",*cc); temp=temp->prev; } /* list*l2=listDup(l); temp=l2->tail; while(temp){ cc=(int *)(temp->value); printf("%d\n",*cc); temp=temp->prev; } */ //listSetMatchMethod(l,&intMatch); listNode*node=listIndex(l,1); int *zhu=(int*)node->value; printf("*zhu:%d\n",*zhu); listRelease(l); //listRelease(l2); system("pause"); return 0; }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 动态字符串SDS的实现 | 自己实现Redis源代码(1)
- 修改golang源代码实现无竞争版ThreadLocal
- 字典与哈希表 | 自己实现Redis源代码(3)
- 修改golang源代码获取goroutine id实现ThreadLocal
- 如何用 Flutter 实现混合开发?闲鱼公开源代码实例
- 兄弟连区块链教程Fabric1.0源代码分析Peer peer chaincode命令及子命令实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。