C語言通用鏈表實現

最近想對自己的知識和技能做一個總結,看到有人在博客上說,最好的知識總結,就是將知識固化,所謂的固化,就是把所學的知識記錄下來,或者寫成筆記或者寫成博客。最近也想實踐一下,就從寫博客開始,之前也把學習的過程通過學習筆記的形式寫成博客,回頭看一下還是有很多好處的,一來作爲一種知識分享,讓想學習同樣知識的同學可以一起學習,二來可以作爲自己學習的回顧,增加自己的學習效果。

總之,不管是學習還是做別的事情,都不能光想,落到實踐上比什麼都重要,尤其是做技術,動手能力非常重要。昨天自己動手寫了一個通用的鏈表庫,這裏將代碼貼出來,寫的不對的地方還請大俠幫忙指正:

頭文件list.h:

/***********************************************************
文件名:list.h
作者:Jerry
日期:2017年04月

轉發或拷貝請將這段註釋一起拷貝
***********************************************************/

#ifndef LIST_H_INCLUDED
#define LIST_H_INCLUDED

#ifdef __cplusplus
extern "C"{
#endif
/*定義錯誤碼*/
enum{
    LIST_OK = 0,    //成功
    LIST_ERR = 1    //失敗
};


typedef struct tagNode{
    struct tagNode *pPrev;
    struct tagNode *pNext;
    void *data;
}LIST_NODE_S;

typedef struct tagList{
    LIST_NODE_S *pHead;
    LIST_NODE_S *pTail;
    unsigned int count;
}LIST_S;


/*迭代器結構*/
typedef LIST_NODE_S LIST_ITER_S;


typedef void(*ListDataFreeFunc)(void*);

/**************************************
功能:初始化空的鏈表
參數:
返回值:指向空鏈表的指針
**************************************/
extern LIST_S *List_Api_New();


/*****************************************
功能:釋放LIST_S結構鏈表,對每一個鏈表結點調用pFunc釋放內存
參數:
    LIST_S *pList,  //鏈表指針
    ListDataFreeFunc pFunc  //結點釋放函數
返回值:void
******************************************/
extern void List_Api_FreeEx(LIST_S *pList, ListDataFreeFunc pFunc);



/***************************************************************
功能:向鏈表尾部插入數據
參數:
    LIST_S *pList    //要插入數據的鏈表,不能爲NULL
    void *data     //要插入的數據,不區分類型,需要用戶申請內存
返回值: 插入成功返回LIST_OK,失敗返回非LIST_ERR
*******************************************************************/
extern int List_Api_Append(LIST_S *pList, void *data);



/************************************************************
功能:獲取指向鏈表第一個元素的迭代器指針
參數:
    LIST_S *pList    //要操作的鏈表
返回值:指向第一個元素的迭代器指針
*************************************************************/
extern LIST_ITER_S *List_Api_Begin(LIST_S *pList);




/************************************************************
功能:獲取指向鏈表最後一個元素的迭代器指針
參數:
    LIST_S *pList       //要操作的鏈表
返回值:指向最後一個元素的迭代器指針
*************************************************************/
extern LIST_ITER_S *List_Api_Last(LIST_S *pList);


/***********************************************************
功能:獲取當前迭代器位置的數據
參數:
    LIST_ITER_S *pIter    //當前迭代器指針
返回值:void *
************************************************************/
extern void *List_Api_GetData(LIST_ITER_S *pIter);


/**********************************************************
功能:獲取當前迭代器的前一個迭代器指針
參數:
    LIST_ITER_S *pIter  
返回值:LIST_ITER_S *
***********************************************************/
extern LIST_ITER_S *List_Api_Previous(LIST_ITER_S *pIter);


/**********************************************************
功能:獲取當前迭代器的後一個迭代器指針
參數:
    LIST_ITER_S *pIter
返回值:LIST_ITER_S *
***********************************************************/
extern LIST_ITER_S *List_Api_Next(LIST_ITER_S *pIter);


/*********************************************************
功能:刪除當前迭代器指向位置的元素
參數:
    LIST_S *pList         //要操作的鏈表,不能爲NULL
    LIST_ITER_S *pIter    //當前迭代器
返回值:下一個迭代器指針
***********************************************************/
extern LIST_ITER_S *List_Api_Delete(LIST_S *pList, LIST_ITER_S *pIter); 


/*********************************************************
功能:獲取當前鏈表長度
參數:LIST_S *pList   //要計算長度的鏈表
返回值:unsigned int
**********************************************************/
extern unsigned int List_Api_GetCount(LIST_S *pList);


#define List_Api_Free(p)   do{if(p) free(p); p = NULL;}while(0)


#ifdef __cplusplus
}
#endif

#endif // LIST_H_INCLUDED

源文件 list.c:

#include "list.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>


LIST_S *List_Api_New(){
    LIST_S *pList;
    pList = (LIST_S *)malloc(sizeof(LIST_S));
    if(NULL != pList) memset(pList, 0, sizeof(LIST_S));
    return pList;
}


void List_Api_FreeEx(LIST_S *pList, ListDataFreeFunc pFunc){
    LIST_ITER_S *pHead, *pNext;

    if(!pList) return;
    assert(pFunc != NULL);

    pHead = pList->pHead;
    while(pHead){
        pNext = pHead->pNext;
        pFunc(pHead->data);
        pHead = pNext;      
    }   

    pList->pHead = NULL;
    pList->pTail = NULL;
    pList->count = 0;
    List_Api_Free(pList);
}


int List_Api_Append(LIST_S *pList, void *data){
    LIST_NODE_S *pNode;
    assert(pList != NULL);
    pNode = (LIST_NODE_S *)malloc(sizeof(LIST_NODE_S));
    if(NULL == pNode){
        return LIST_ERR;
    }
    memset(pNode, 0, sizeof(LIST_NODE_S));
    pNode->data = data;
    if(pList->pHead == NULL){
        pList->pHead = pNode;   
        pList->pTail = pList->pHead;
    }
    else {
        //掛接結點
        pList->pTail->pNext = pNode;
        pNode->pPrev = pList->pTail;
        //更新鏈表尾結點
        pList->pTail = pList->pTail->pNext;
    }
    pList->count ++;

    return LIST_OK;
}

void *List_Api_GetData(LIST_ITER_S *pIter){
    assert(pIter != NULL);

    return pIter->data;
}

LIST_ITER_S *List_Api_Begin(LIST_S *pList){
    if(!pList) return NULL;
    return (LIST_ITER_S*)(pList->pHead);    
}

LIST_ITER_S *List_Api_Last(LIST_S *pList){
    if(!pList) return NULL;
    return (LIST_ITER_S*)(pList->pTail);
}


LIST_ITER_S *List_Api_Previous(LIST_ITER_S *pIter){
    assert(pIter !=NULL);
    return pIter->pPrev;
}

LIST_ITER_S *List_Api_Next(LIST_ITER_S *pIter){
    assert(pIter != NULL);
    return pIter->pNext;
}

LIST_ITER_S *List_Api_Delete(LIST_S *pList, LIST_ITER_S *pIter){
    LIST_ITER_S *pHead = NULL;
    LIST_ITER_S *pTail = NULL;
    if(!pList) return NULL;

    assert(pIter != NULL);

    pHead = pList->pHead;
    pTail = pList->pTail;

    if(pIter == pHead){
        pList->pHead = pIter->pNext;
        pList->pHead->pPrev = NULL;
        pList->count --;
        pIter->pPrev = NULL;
        pIter->pNext = NULL;
        return pList->pHead;
    }   

    if(pIter == pTail){
        pList->pTail = pList->pTail->pPrev;
        pList->pTail->pNext = NULL;
        pList->count --;
        pIter->pPrev = NULL;
        pIter->pNext = NULL;
        return NULL;
    } 

    while(pHead != pIter && pHead != pTail){
        pHead = pHead->pNext;
    }

    if(pHead == pTail){
        return NULL;
    }

    pHead = pIter->pPrev->pNext = pIter->pNext;
    pIter->pNext->pPrev = pIter->pPrev;
    pList->count --;

    pIter->pNext = NULL;
    pIter->pPrev = NULL;

    return pHead;
}

unsigned int List_Api_GetCount(LIST_S *pList){
    if(!pList) return 0;
    return pList->count;
}

下面的這段代碼可以對上面的接口進行測試:

#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct testData{
    char *name;
    int age;
}STUDENT_S;


static STUDENT_S *Student_New(char *name, int age){
    STUDENT_S *stu;
    stu = (STUDENT_S*)malloc(sizeof(STUDENT_S));
    if(!stu) return NULL;
    memset(stu, 0, sizeof(STUDENT_S));
    stu->name = strdup(name);
    stu->age = age;
    return stu;
}

static void Student_Free(STUDENT_S *pStu){
    if(!pStu) return ;
    if(pStu->name) free(pStu->name);
    free(pStu);
}

int main(int argc, char **argv){
    int *val = NULL, i;
    int iRet;
    STUDENT_S students[] = {
        {"xiaoming", 15},
        {"xiaohua", 16},
        {"xiaofang", 16}
    };
    LIST_ITER_S *pstIter = NULL;

    LIST_S *pList = List_Api_New();
    if(!pList){
        fprintf(stderr, "out of memory");
        exit(1);
    }

    for(i = 0; i < sizeof(students)/sizeof(students[0]); i ++){
        STUDENT_S *pStu = Student_New(students[i].name, students[i].age);
        if(!pStu){
            fprintf(stderr, "out of momory");
            List_Api_FreeEx(pList, (void(*)(void*))Student_Free);
            exit(1);
        }
        iRet = List_Api_Append(pList, pStu);
        if(iRet != LIST_OK){
            Student_Free(pStu);
        }
        pStu = NULL;
    }   


    printf("\ncount: %u\n", List_Api_GetCount(pList));
    printf("output from first to last\n");
    pstIter = List_Api_Begin(pList);
    while(pstIter != NULL){
        STUDENT_S *v = (STUDENT_S *)List_Api_GetData(pstIter);
        if(v)
        {   
            printf("Name: %s\n", v->name);
            printf("Age: %d\n", v->age);
        }
        pstIter = List_Api_Next(pstIter);
    }


    printf("\noutput from last to first\n");
    pstIter = List_Api_Last(pList);
    while(pstIter != NULL){
        STUDENT_S *v = (STUDENT_S *)List_Api_GetData(pstIter);
        if(v)
        {   
            printf("Name: %s\n", v->name);
            printf("Age: %d\n", v->age);
        }
        pstIter = List_Api_Previous(pstIter);
    }

    printf("\nDelete first student\n");
    pstIter = List_Api_Begin(pList);
    //pstIter = List_Api_Next(pstIter);  //如果要刪除中間的一個,將這一句前面的註釋去掉
    (void)List_Api_Delete(pList, pstIter);

    Student_Free((STUDENT_S*)(pstIter->data));

    printf("\nnow count: %u\n", List_Api_GetCount(pList));
    printf("left students are:\n");
    pstIter = List_Api_Begin(pList);
    while(pstIter != NULL){
        STUDENT_S *v = (STUDENT_S *)List_Api_GetData(pstIter);
        if(v)
        {   
            printf("Name: %s\n", v->name);
            printf("Age: %d\n", v->age);
        }
        pstIter = List_Api_Next(pstIter);
    }

    List_Api_FreeEx(pList, (void(*)(void*))Student_Free);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章