[數據結構]單鏈表C語言的簡單實現

Github:(https://github.com/FlameCharmander/DataStructure)
本來是在和順序表裏放一起寫。但是考慮簡潔的話,就這樣寫了。
直接上鍊表的代碼了。

#include <stdio.h>
#include <stdlib.h>

typedef char ElemType;
typedef int BOOL;
#define TRUE 1
#define FALSE 0

typedef struct LinkNode{
    ElemType data;
    struct LinkNode* next;
}LinkList, Node;

void InitList(LinkList *list);   //初始化鏈表
BOOL Insert(LinkList *list, ElemType e, int pos);   //將元素插入
BOOL Delete(LinkList *list, ElemType e);    //將指定元素刪除
BOOL IsEmtpy(LinkList *list);   //判斷鏈表是否爲空

int main()
{
    LinkList list;
    InitList(&list);
    printf("%d\n", IsEmtpy(&list));
    Insert(&list, 'a', 1);
    Insert(&list, 'b', 2);
    Insert(&list, 'c', 1);
    Delete(&list, 'a');
    Node *p = list.next;
    while (p != NULL) {
        printf("%c ", p->data);
        p = p->next;
    }
    printf("\n%d\n", IsEmtpy(&list));
    Delete(&list, 'b');
    Delete(&list, 'c');
    printf("%d\n", IsEmtpy(&list));
    return 0;
}

void InitList(LinkList *list){
    list->next = NULL; //設置一個頭結點
}

BOOL Insert(LinkList *list, ElemType e, int pos){
    int i;
    Node* pre = list;
    for (i = 1; i < pos; ++i){
        pre = pre->next;
    }
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = e;
    node->next = pre->next;
    pre->next = node;
    return TRUE;
}

BOOL Delete(LinkList *list, ElemType e){
    Node* pre = list;
    while (pre->next != NULL) {
        if (pre->next->data == e){
            Node* q = pre->next;    //臨時存儲
            pre->next = pre->next->next;
            free(q);
            return TRUE;
        } else {
            pre = pre->next;
        }
    }
    return FALSE;
}

BOOL IsEmtpy(LinkList *list){
    if (list->next == NULL) {
        return TRUE;
    } else {
        return FALSE;
    }
}

老規矩,要對代碼做一個解釋了,可以再開窗口對照着看。
Line 1~2 是導入頭文件
Line 4 Typedef是給用來爲複雜的聲明定義簡單的別名,所以這裏我這裏設置ElemType char,如果到時鏈表的元素類型不是char,比如只要int,只需typedef int ElemType。
Line 5~7 由於C語言沒有布爾類型,所以這裏用了int代替,1代表True,0代表False
Line 9~12 這是鏈表的數據結構,如果不太熟的話,去看看理論部分吧。
Line 14~17 函數的聲明,如果函數寫在main函數下面,需要在這裏做個定義
Line 19~38 這裏是main函數,就是將所寫的操作給測試一下,看有沒有出錯
Line 40~42 這裏默認鏈表是有頭結點的,這樣插入和刪除等會方便很多,如果你不知道頭結點是什麼,我簡單說下,頭結點就是一個沒有值的結點,下面會講爲什麼需要投結點。
Line 44~55 這就是我們的插入操作了。1<=pos<=n。
Line 46 pre代表是前一個結點的意思。我畫了張圖,是鏈表插入了元素a,b之後的圖。
插入a和b之後的鏈表
第一個沒有值的結點就是頭結點了,現在我們要插入c到1的位置,也就是a的前面,那麼我們需要a之前的結點(現在這個結點是頭結點)才能把c插入到a的前面對吧。
那你試想下,如果沒有頭結點的話,那是不是還要判斷插入結點是第一個結點還是第一個結點之後。(你們想象下沒有頭結點的插入就知道了)
Line 47~49 這個是尋找要插入的位置的前一個結點
Line 50~51 申請一個新的結點,並把要插入的元素(現在是c)賦值到數據域,我們即將要把它插入到我們想要的位置。
Line 52~54 看下下面這個圖
插入c

node->next = pre->next;將c的指針域指向到a
pre->next = node;將pre結點(現在是頭結點)的指針域指向c
然後返回真,這就完成了一次插入操作,請注意,我們要插入一個結點,需要的是前一個結點。
Line 57~70 刪除操作
我們把剛纔的插入完C的表重新調整一下。
插入C之後的鏈表
Line 59 是遍歷全部結點
刪除a
Line 60 是找到要刪除的結點的前一個結點
Line 61 用指針q指向結點a,看圖
Line 62 比如現在找到了c(a的前一個結點),那我們要把a刪除,把c的指針域指向b結點即可
Line 63 這時結點a就沒有了任何存在的意義了,我們需要手動釋放它,這裏的Line 61~63的順序是不能換的,耐人尋味。爲什麼不能先釋放呢,因爲我們如果先釋放了,那我們c結點就找不到a結點的後一個結點b了
Line 72~78 由於有頭結點,所以判斷的條件next是否爲空。

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