經過對《Redis設計與實現》一書的學習,我打算動手本身實現一份「Redis源代碼」做爲本身的學習記錄。node
對Redis感興趣的同窗能夠查看個人另外一篇文章 造個輪子 | 本身動手寫一個Redis。segmentfault
本章介紹的是Redis源代碼中的雙端鏈表list的實現。函數
list *listCreate(void);學習
void listRelease(list *l);this
list listAddNodeHead(list l, void *value);設計
list listAddNodeTail(list l, void *value);指針
list listInsertNode(list l, listNode old_node, void value, int after);code
list listDelNode(list l, listNode *node);索引
list listDup(list orig);ip
listNode listSearchKey(list l, void *key);
listNode listIndex(list l, long index);
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
#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; }