雙端鏈表list的實現 | 自己實現Redis源代碼(2)

通過對《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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章