1. 程式人生 > >自己編寫連結串列函式庫詳解

自己編寫連結串列函式庫詳解

標頭檔案

#ifndef _LINKLIST_H
#define _LINKLIST_H

#define SUCCESS 10000
#define FAILURE 10001
#define TRUE    10002
#define FALSE   10003

typedef int ElemType;

struct node
{
    ElemType data;      //資料域
    struct node *next;  //指標域
};

typedef struct node Node;

int InitLinkList(Node **l);
int InsertLinkList(Node *l, int n, ElemType e);
int TraverseLinkList(Node *l, void(*p)(ElemType));
int LinkList_Len(Node *l);
int LinkListEmpty(Node *l);
int GetElem(Node *l, int n, ElemType *e);
int LocateElem(Node *l, ElemType e, int (*p)(ElemType,ElemType));
int DeleteLinkList(Node *l, int p, ElemType *e);
int ClearLinkList(Node *l);      
int DestroyLinkList(Node **l);
int ReverseLinkList(Node *l);

#endif

函式庫

#include "LinkList.h"
#include <stdlib.h>

//初始化條件:結構體指標已存在,並且傳入函式
//引數:Node **l l是一個指標,l的型別是Node **,l指向的型別是Node *
//函式功能:建立一個首結點,該結點指標域為NULL
int InitLinkList(Node **l)
{
    (*l) = (Node *)malloc(sizeof(Node) * 1);
    if(NULL == *l)
    {
        return FAILURE;
    }

    (*l)->next = NULL;

    return SUCCESS;
}

//初始化條件;頭指標傳入函式,位置n不大於連結串列的長度
//引數:l 頭指標 n 要插入的位置 e 要插入的資料
//函式功能:在連結串列中新插入一個結點
int InsertLinkList(Node *l, int n, ElemType e)
{
    Node *p = l;                //定義一個指標指向頭結點
    int k = 1;                      //移動的次數

    if (NULL == l)              //入參判斷
    {
        return FAILURE;
    }

    while (k < n && p != NULL)  //p移動到指向要插入位置前一個結點
    {
        p = p->next;
        k++;
    }

    if (k > n || NULL == p) //所有意外情況都包含進去了
    {
        return FAILURE;
    }

    Node *q = (Node *)malloc(sizeof(Node) * 1); //  給新節點分配空間
    if (NULL == q)          //檢查是否分配成功
    {
        return FAILURE;
    }

    q->data = e;            //給新建立的結點賦值
    q->next = p->next;      //新結點指向原來n處的結點
    p->next = q;            //原來n的前一個結點指向新結點

    return SUCCESS;
}

//初始化條件,頭指標傳入函式
//引數:l 頭指標 p 函式指標,指向輸出函式
//函式功能:逐個輸出連結串列每個結點的值
int TraverseLinkList(Node *l, void(*p)(ElemType))
{
    Node *q = l;                //定義一個指標指向頭結點

    if (NULL == l)               //入參判斷
    {
        return FAILURE;
    }

    while (q->next != NULL)     //當q指向最後一個結點的時候結束迴圈
    {
        q = q->next;            //q指向後一個結點
        p(q->data);             //輸出q指向結點的資料
    }

    return SUCCESS;
}

//初始化條件:頭指標傳入函式
//引數:l頭指標
//函式功能:求出連結串列的長度
int LinkList_Len(Node *l)
{
    if (NULL == l)
    {
        return FAILURE;
    }

    int len = 1;
    Node *p = l->next;

    while (p)
    {
        len++;
        p = p->next;
    }

    return len;
}

//初始化條件:
//引數 l 頭指標
//函式功能,判斷連結串列是否為空
int LinkListEmpty(Node *l)
{
    return (NULL == l->next) ? TRUE : FALSE; //頭結點之後沒有結點,為空連結串列
}

//初始化條件:頭指標傳入函式,結點n不小於1,結點n要存在
//引數: l 頭指標 n 要檢視的位置 e 儲存檢視的那個結點的資料
//函式功能:得到連結串列中第n個結點的資料並返回其值
int GetElem(Node *l, int n, ElemType *e)
{
    if (NULL == l || n < 1)
    {
        return FAILURE;
    }

    Node *p = l;
    int i;

    for (i = 0; i < n && p != NULL; i++)
    {
        p = p->next;
    }

    if (!p)
    {
        return FAILURE;
    }

    *e = p->data;
    
    return SUCCESS;
}

//初始化條件:頭指標傳入函式
//引數 l 頭指標 e 要查詢的元素 p 函式指標 指向比較函式
//函式功能:檢視e在連結串列中的第幾個結點
int LocateElem(Node *l, ElemType e, int (*p)(ElemType,ElemType))
{
    if (NULL == l)                  //入參判斷
    {
        return FAILURE;
    }

    Node *q = l->next;              //定義一個結點指向第一個節點
    int len = 1;                    //結點的個數

    while (q)                       //挨個比較e與結點資料是否相等
    {   
        if (TRUE ==p(e,q->data))    //如果相等,返回第幾個結點
        {
            return len;
        }
        q = q->next;                //指向下一個結點
        len++;                      //結點個數加1
    }

    return FAILURE;                 //如果沒有,返回失敗
}

/*
 *引數: l 頭指標
 *      p 要刪除的位置,不能大於連結串列長度,不能小於1 
 *      e要儲存p處結點的資料
 *函式功能:刪除p處結點,並儲存其資料域的值
 *返回值:SUCCESS/FAILURE
 */
int DeleteLinkList(Node *l, int p, ElemType *e)
{
    if (NULL == l)              //入參判斷
    {
        return FAILURE;
    }

    int k = 1;                  //移動次數
    Node *q = l;

    while (k < p && q != NULL)
    {
        q = q->next;
        k++;
    }
                                //找到要刪除的位置前一個結點
    if (k > p || NULL == q)
    {
        return FAILURE;
    }

    Node *n = q->next;          //定義一個指標指向要刪除的結點
    *e = n->data;               //儲存要刪除結點的資料
    q->next = n->next;      //將要刪除的結點與要刪除的結點後面一個結點建立聯絡
    free(n);                //釋放給要刪除結點分配的空間

    return SUCCESS;
}

/*
 *引數:l 頭指標
 *實現功能:刪除除了頭結點外的所有結點
 *返回值:SUCCESS/FAILURE
 */
int ClearLinkList(Node *l)
{
    if (NULL == l)              //入參判斷
    {
        return FAILURE; 
    }
    
    Node *p = l->next;          //指標p指向第一個結點
    while (p)                   //while迴圈刪除第一個結點以後所有結點
    {
        l->next = p->next;      
        free(p);
        p = l->next;
    }

    return SUCCESS;
}


/*
 * 引數:l頭指標 不為空
 * 實現功能:銷燬連結串列,釋放為連結串列分配的空間
 * 返回值:SUCCESS/FAILURE
 */
int DestroyLinkList(Node **l)
{
    if (NULL == l)          //入參判斷
    {
        return FAILURE;
    }

    free(*l);               //釋放連結串列空間
    *l = NULL;              //不變為空指標,會成野指標,記憶體洩漏

    return SUCCESS;
}

/*
 *引數:l 頭指標 不為空
 *實現功能:反轉連結串列
 *返回值:TRUE/FALSE
 */
int ReverseLinkList(Node *l)
{
    if (NULL == l)          //入參判斷
    {
        return FAILURE;
    }

    Node *p = l->next;      //p指向第一個結點
    l->next = NULL;         //首結點與第一個結點斷開

    while (p)               //執行迴圈直到最後一個結點
    {
        Node *q = p;        //指標q指向p
        p = p -> next;      //p指向下一個結點
        q->next = l->next;  //將q結點與頭結點後面一個結點相連
        l->next = q;        //頭結點與q相連
    }

    return SUCCESS;
}