C語言——基礎鏈表詳解


敢於向黑暗宣戰的人,心里必須充滿光明。

 


 

一、鏈表的構成

1.構成

鏈表是由一連串的結構(稱為結點)組成的。

(1)結點的構成:

數據(要儲存的數據)+指針(指向下一個結點的指針)

(2)關於幾個定義

頭結點:鏈表首結點前的一個結點(不是必須的,但是如果有就可以在解決某些問題時候方便一些,通常可以用來儲存鏈表的長度等信息)

首結點:鏈表的第一個數據元素

頭指針:必須要有的(而頭結點可以沒有,注意兩者一個是指針一個是結點,一個必須有一個可以沒有),指向頭結點/首節點的指針(永遠指向鏈表的第一個結點)

2.結點類型聲明、創建結點

struct node{
    int value;
    struct node *next;//創建了一個指向一個node類型的指針,用於指向下一個結點
};
//至此聲明了一個結點類型

//頭指針:
struct node *first = NULL;

//結點創建:

struct node *new_node;
new_node = (struct node *)malloc(sizeof(struct node));//給結點分配內存單元。注意:malloc返回的是void類型的指針,所以可以強制類型轉換一下
new_node -> value = 10;//把數據存儲到結點中

二、在鏈表開始處插入結點

struct node * first = NULL;

struct node *new_node;
new_node =(struct node *)malloc(sizeof(struct node));
new_node ->value = 10;

//將new_node結點插入鏈表開始處

new_node->next = first;//new_node指向的node類型的next值為NULL,NULL可作為鏈表結尾(空指針)
first = new_node;//讓first 指向 new_node指向的結點(其實就是剛才malloc出來的結點)

//ok至此,現在就已經有了一個鏈表,它有一個結點,結點中儲存的值是10

new_node = (struct node*)malloc(sizeof(struct node));
new_node ->value = 2;
new_node->next = first;//又新創建了個結點並讓next指向第一次創建的結點(因為first是指向第一次創建的結點的)
first = new_node;//可以理解為把頭指針重置到頭部

我們把它封裝成函數

對於這樣的函數我們傳入一個鏈表list,和一個希望存入鏈表的數值n

struct node* add_to_list(struct node *list,int n)
{
    sturct noed *new_node;
    new_node = (struct node*)malloc(sizeof(struct node));
    if(new_node == NULL)
    {
        printf("malloc error\n");
        exit(0);
    }
    new_node->value = n;
    new_node->next = list;//把新結點接到鏈表中
    return new_node;
}



first = add_to_list(first,10);
first = add_to_list(first,20);
//需要注意的是add_to_list函數是沒有辦法修改指針的(因為這個相當於復制了一個指針傳進去,能修改它指向的東西,但是沒有辦法對他本身進賦值存儲)
//所以我們返回一個指向新結點的指針,讓他作為返回值賦值儲存給first

需要注意的是add_to_list函數是沒有辦法修改指針的(因為這個相當於復制了一個指針傳進去,能修改它指向的東西,但是沒有辦法對他本身進賦值存儲),所以我們返回一個指向新結點的指針,讓他作為返回值賦值儲存給first

三、搜索鏈表

while循環可以用,但是我們都知道for循環是很靈活的。這是一張訪問鏈表中結點的習慣方法:

[慣用方法]
for (p = first; p !=NULL; p = p->next)

...

這里可以使用指針變量p來追蹤結點,p = p->next 就能實現了讓p從一個結點移動到下一個結點

第一種方法:

struct node* search_list(struct node *list,int n)
{
    struct node *p;

    for(p = list; p != NULL; p = p->next)
    {
        if(p -> value == n)
            return list;
    }
    return NULL;

}

第二種方法:

struct node *search_list(struct node *list,int n)
{
    for(;list != NULL;list = list->next)
    {
        if(list->next == n)
            return list;
    }
    return NULL;
}

這里list是原始鏈表指針的副本,所以在函數中對他改變是沒有損害的

四、從鏈表中刪除結點

步驟:

1.定位要刪除的結點(搜索鏈表)

2.改變前一個結點的指向,從而使鏈表“繞過”希望刪除的結點

3.調用free函數收回期望刪除的結點占用的內存空間

一種方法:“追蹤指針”法,在搜索鏈表時總是保留一個指向前一個結點的指針(prev)還有一個指向當前指針的結點(cur)。

如下:(list是帶搜索鏈表,n是要刪除的整數)

for(cur = list,prev = NULL;cur != NULL && cur->value != n;prev = cur,cur = cur ->next);
prev->next = cur->next;//條件為假,結束循環,讓prev指向cur的下一個結點從而完成“繞過”操作

注意:表達式3是每次循環中最后一次被執行的操作

然后在free掉cur,讓prev指向next

封裝成函數:

struct node *delete_list(struct node *list,int n)

{
    struct node *prev,*cur;
    
    for(cur = list,prev = NULL;cur != NULL && cur->value != n;prev = cur,cur = cur->next);
    //這個for循環只是為了找到希望刪除的結點即value等於n的結點
    if(cur == NULL)//找到了最后也沒找到要刪除的結點,不用刪除,返回list
        return list;
    if(prev == NULL)//條件為假,未執行for循環,即首結點為n,直接讓list指向下一個結點來繞過即可
        list = list->next;//對於刪除鏈表中的首結點是一種特殊情況,需要特殊判斷特殊繞過他。
    else
        prev->next = cur->next;//繞過要刪除的結點
    free(cur);//釋放掉被刪除的結點的內存
    return list;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM