1. 程式人生 > >線性表(三)——線性連結串列(單鏈表)

線性表(三)——線性連結串列(單鏈表)

線性連結串列(單鏈表)

構造原理

用一組地址任意的儲存單元(連續的或不連續的)依次儲存表中各個資料元素, 資料元素之間的邏輯關係通過指標間接地反映出來。
在這裡插入圖片描述
線性表的這種儲存結構稱為線性連結串列,又稱為單鏈表。
在C語言中線性連結串列的定義如下:

typedef struct node { 
    ElemType data;
    struct node *link;
}LNode, *LinkList;          //定義一個線性連結串列型別
//上述程式碼相當於給結構體 node 定義了一個別名LNode和一個指標別名LinkList


LinkList list;                //宣告一個線性連結串列List,List為整個線性連結串列的頭指標
//等價於 struct node *list; 等價於 LNode *list;

基本操作

1、求線性連結串列的長度
1、非遞迴演算法:

int LENGTH( LinkList list ){
    LinkList p=list;
    int n=0;        /* 連結串列的長度置初值0*/
    while(p!=NULL){
        p=p->link;
        n++;
    }
    return n;       /* 返回連結串列的長度n */
}

此演算法的時間複雜度O(n)
2、遞迴演算法:

int LENGTH(LinkList list){
    if(list != NULL)
        return 1+LENGTH( list->link);
    else 
        return 0;
}

連結串列本身就是一種遞迴結構,但遞迴演算法時間效率往往比非遞迴低。

2、建立一個線性連結串列
從頭到尾建立連結串列

LinkList CREATE( int n ){
    LinkList p, r, list=NULL;
    datatype a;
    for(i=1;i<=n;i++){
        READ(a);          /* 取一個數據元素*/
        p=(LinkList)malloc(sizeof(LNode));        //申請一個新的鏈結點   需要引入alloc.h
        p->data=a;
        p->link=NULL;
        if (list==NULL)
            list=p;
        else
            r->link=p;           /* 將新結點連結在連結串列尾部*/
        r=p;                        //指標變數r總是指向連結串列末尾
    }
    return list;
}

該演算法的時間複雜度O(n)
3、在非空線性連結串列的第一個結點前插入一個數據信息為item 的新結點

void INSERTLINK1( LinkList &list, ElemType item ){
    //list存放連結串列的首地址
    LinkList p;
    p=(LinkList)malloc(sizeof(LNode));
    p->data=item;                /* 將item送新結點資料域*/
    p->link=list;                   /* 將list送新結點指標域*/
    list=p;                           /* 修改指標list的指向*/ 
}

該演算法的時間複雜度為O(1),與連結串列長度n無關
4、線上性連結串列中由指標q 指的鏈結點之後插入一個數據信息為item 的鏈結點

void INSERTLINK2( LinkList &list, LinkList q,ElemType item ){ 
    LinkList p;
    p=(LinkList)malloc(sizeof(LNode));
    p->data=item;          /* 將item送新結點資料域*/
    if (list==NULL) {       /* 若原連結串列為空*/
        list=p;
        p->link=NULL; 
    }else{            /* 若原連結串列為非空*/
        p->link=q->link;
        q->link=p;
    }
}

該演算法的時間複雜度為O(1),與連結串列長度n無關
4、從非空線性連結串列中刪除q指的鏈結點,設q的直接前驅結點由r指出

void DELETELINK1( LinkList &list, LinkList r, LinkList q ){
    if (q==list) 
        list=q->link;                /* 刪除連結串列的第一個鏈結點*/
    else
        r->link=q->link;          /* 刪除q指的鏈結點*/
    free(q);                          /* 釋放被刪除的結點空間*/
}

該演算法的時間複雜度為O(1),與連結串列長度n無關
5、從非空線性連結串列中刪除q指的鏈結點,不知q的直接前驅節點
比4增加了一個尋找q直接前驅節點r的過程

void DELETELINK2( LinkList &list, LinkList q ){
    LinkList r;
    if (q==list) {      /*當刪除連結串列第一個結點*/
        list=list->link;
        free(q);        /*釋放被刪除結點的空間*/
    }else {
        r=list;                             //尋找q的直接前驅節點r
        while( r->link!=q &&r->link!=NULL) 
            r=r->link;      /*移向下一個鏈結點*/
        if (r->link!=NULL){ 
            r->link=q->link;
            free(q); 
        }
    } 
}

該演算法的時間複雜度為O(n)

線性錶鏈式儲存結構的特點

1、優點
(1)儲存空間動態分配,可以根據實際需要使用。
(2)不需要地址連續的儲存空間。
(3)插入/刪除操作只須通過修改指標實現,不必移動資料元素,操作的時間效率較高。(無論位於連結串列何處,無論連結串列的長度如何,插入和刪除操作的時間都是Ο(1))
2、缺點
(1)每個鏈結點需要設定指標域(儲存密度小)。
(2)是一種非隨機儲存結構,查詢、定位等操作要通過順序掃描連結串列實現,時間效率較低。(時間為Ο(n))