鏈表詳細知識點

一、鏈表原理

(1)鏈表的組成

        鏈表是由若干個節點組成的(鏈表的各個節點結構是完全類似的),節點是由有效數據和指針組成的。有效數據區域用來存儲信息完成任務的,指針區域用於指向鏈表的下一個節點從而構成鏈表。

(2)鏈表的作用

        時刻謹記:鏈表就是用來解決數組的大小不能動態擴展的問題,所以鏈表其實就是當數組用的。直白點:鏈表能完成的任務用數組也能完成,數組能完成的任務用鏈表也能完成。但是靈活性不一樣。

        簡單說:鏈表就是用來存儲數據的。鏈表用來存數據相對於數組來說優點就是靈活性,需要多少個動態分配多少個,不佔用額外的內存。數組的優勢是使用簡單(簡單粗暴)。      

二、鏈表構成  

1、單鏈表的實現

 

    (1)單鏈表是由節點組成的,節點中包含:有效數據和指針。

                struct node

                {

                        int data;

                        struct node *pNext;

                }

    (2)定義的struct node只是一個結構體,本身並沒有變量生成,也不佔用內存。結構體定義相當於爲鏈表節點定義了一個模板,但是還沒有一個節點,將來在實際創建鏈表時需要一個節點時用這個模板來複制一個即可。 

                            

    (3)  頭指針pheader(每個鏈表都會有一個頭)

        頭指針並不是節點,而是一個普通指針,只佔4字節。頭指針的類型是struct node *類型的,所以它才能指向鏈表的節點。              

2、創建一個鏈表節點

    (1)鏈表的內存要求比較靈活,不能用棧,也不能用data數據段。只能用堆內存。

    (2)用堆內存來創建一個鏈表節點的步驟:

                1、申請堆內存,大小爲一個節點的大小(檢查申請結果是否正確);

                2、清理申請到的堆內存;

                3、把申請到的堆內存當作一個新節點;

                4、填充你哦個新節點的有效數據和指針區域。

            代碼如下:

                struct node *pHeader = NULL;
                /********************************************************************/
                // 每創建一個新的節點,把這個新的節點和它前一個節點關聯起來
                // 創建一個鏈表節點       malloc返回一個int指針,指向存放數據的地址,這裏強制轉換
                struct node *p = (struct node *)malloc(sizeof(struct node));
                if (NULL == p)
                {
                        printf("malloc error.\n");
                        return -1;
                }
                // 清理申請到的堆內存
                bzero(p, sizeof(struct node));
                // 填充節點
                p->data = 1;
                p->pNext = NULL; // 將來要指向下一個節點的首地址
                // 實際操作時將下一個節點malloc返回的指針賦值給這個

                pHeader = p; // 將本節點和它前面的頭指針關聯起來

 

3、鏈表頭尾插入分析代碼

 

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


struct node 
{
        int data ;
        struct node *pNext;
};


struct node *pHeader = NULL;

// 作用:創建一個鏈表節點
// 返回值:指針,指針指向我們本函數新創建的一個節點的首地址
struct node * creat_node(int data)
{
        struct node *p = (struct node *)malloc(sizeof(struct node));
        if(NULL == p)
        {
                printf("fail/n");
                return NULL;
        }
        bzero(p,sizeof(struct node));
        p->data = data;
        p->pNext = NULL;
        return p;
}



//作用:尾部插入一個節點
void insert_tail(struct node *pH,int data)
{
        struct node *p = pH;
        while(NULL  != p->pNext)          //找到最後一個指向NULL的指針,就是鏈表的最後一個節點
        {
                p = p->pNext;        //這也是鏈表遍歷的方法
        }
        p->pNext = creat_node(data);     //將新節點插入到最後一個節點尾部

}


void insert_head(struct node *pH,int data)
{
        struct node *p = pH;
        struct node *new = creat_node(data);

        //新的節點的pNext指向空節點之前指向的節點首地址

        new->pNext = pH->pNext;           

         //將空節點的pNext指針指向新節點的首地址;pH->pNext裏面的值就是結構體指針

        //new裏面的值(新節點malloc後在內存中分配的實際地址)

        pH->pNext = new;                        

}


int main()
{
        pHeader = creat_node(0);

        insert_tail(pHeader,5);
        insert_head(pHeader,8);
        insert_tail(pHeader,6);
        printf("pHeader->data =  %d\n",pHeader->data);
        printf("pHeader->data =  %d\n",pHeader->pNext->data);
        printf("pHeader->data =  %d\n",pHeader->pNext->pNext->data);
        printf("pHeader->data =  %d\n",pHeader->pNext->pNext->pNext->data);
}

4、鏈表刪除節點

(1)首先我們傳入一個鏈表的頭指針,傳入的鏈表有N個節點

int delate_link(struct node *pH,int data)
{
        struct node *p = pH;
        struct node *pPrev = NULL;
        while(NULL != p -> pNext)

        {

                //將先前的指針保存,不能保存pPrev = p ->pNext,p ->pNext已經指向了下一個節點的首地址

                //所以pPrev保存的是下一個節點的首地址,pPrev = p;  之後再pPrev ->pNext

                pPrev = p;                  //保存被刪節點前面的節點首地址
                p = p -> pNext;
                if(p -> data == data)
                {
                        pPrev -> pNext = p -> pNext; //被刪節點前節點pNext指向被刪節點的後一個節點的首地址
                        free(p);
                        return 0;
                }
        }
        return 0;

}

 

5 鏈表的反轉

int reserve(struct node *pH)
{
        struct node *p = pH->pNext;
        struct node *plast;
        if(NULL == p || NULL == p -> pNext)
        return 0;

        while(NULL != p -> pNext)
        {
                plast = p -> pNext;
                if(p == pH->pNext)
                {
                        p -> pNext = NULL;
                }
                else
                {
                        p -> pNext  = pH -> pNext;
                        pH -> pNext = p;
                }
                p = plast;
        }
        insert_head(pHeader,p->data);
}

6,雙鏈表與單鏈表對比

    (1)很多時候我們都用的是雙鏈表,雖然每個節點多佔用一個指針(4個字節),但是可以忽略,雙鏈表在做刪除節點和插入節點等操作時,會快很多,比如不需要定義plast,pPrev,去保存可能被斷開的節點地址,因爲他有雙向指針,裏面有前前後後所以地址的保存。

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