1. 程式人生 > >線性表——單鏈表的概念

線性表——單鏈表的概念

線性表---單鏈表

typedef struct node {
    ElemType data; //資料域
    struct node *next; //指標域
}LNode, *LinkList; // LinkList為指向LNode型別的指標

結點:資料元素的儲存映像

連結串列:n個結點連結成起來形成一個連結串列,即為線性表的 鏈式儲存結構

單鏈表: 結點中只包含一個指標域

  1. 頭指標:指向連結串列中第一個結點(或為頭結點、或為首元結點)的指標

  2. 頭結點:在連結串列的首元結點之前附設的一個結點;資料域內只放表長等資訊,它不計入表
    長度。其作用是統一空表、和非空連結串列的形式

  3. 首元結點:指連結串列中儲存線性表第一個資料元素a1的結點

線性表的鏈式表示和實現

圖1


(1)單鏈表的建立

  1. 先開闢頭指標,建立頭結點;
  2. 為每個新元素開闢儲存空間,並賦值
  3. 將新結點連結到表尾

1、尾插法

/*例1:用尾插法建立26個字母的帶表頭結點的單鏈表*/
/*演算法1-1*/
LinkList createLinkList1() //尾插法建立帶表頭結點的單鏈表
{ 
    LNode *L,*p,*s; //L頭指標, p指向尾結點, s指向新結點
    L=(LNode *) malloc(sizeof(LNode)); //申請空白結點, L指向頭結點
    L->next =NULL; //建立了頭結點
    p=L; //p指向當前的尾結點
    for(i=1;i<=26;i++)
    {
        s=(LNode *) malloc(sizeof(LNode)); //申請空白結點, s指向
        s->data=i+‘a’-1; //給s->data 賦值
        p->next=s; s->next =NULL; //s指向的結點插入單鏈表的表尾
        p=s; //p總是指向當前連結串列的尾結點 , 等價於p=p->next
    }
    return L;
}
/*演算法1-2*/
void createLinkList2(LinkList *L)
{
    //尾插法建立帶表頭結點的單鏈表 ,L指向頭結點的指標的指標
    Lnode *p,*s; //p指向尾結點, s指向新結點
    *L=(LNode *) malloc(sizeof(LNode)); //申請空白結點, *L指向頭結點
    if (*L==NULL) exit(0);
    *L->next =NULL; //建立了頭結點
    p=*L; //p指向當前的尾結點
    for(i=1;i<=26;i++)
    { 
        s=(LNode *) malloc(sizeof(LNode)); //申請空白結點, s指向
        if (!s) exit(0);
        s->data=i+‘a’-1; //給s->data 賦值
        p->next=s; s->next =NULL; //s指向的結點插入單鏈表的表尾
        p=s; //p總是指向當前連結串列的尾結點 , 等價於p=p->next
    }
}

2、頭插法

/*例2:用頭插法建立26個字母的帶表頭結點的單鏈表*/
/*演算法2-1*/
LinkList createLinkList1() /頭插法建立帶表頭結點的單鏈表
{
    LNode *L,*s;     //L頭指標, s指向新結點
    L=(LNode *) malloc(sizeof(LNode));  //申請空白結點, L指向頭結點
    L->next =NULL; //建立了頭結點
    for(i=26;i>=1;i--)
    { 
        s=(LNode *) malloc(sizeof(LNode));  //申請空白結點, s指向
        s->data=i+‘a’-1; //給s->data 賦值
        s->next=L->next;
        L->next =s; //s指向的結點插入頭結點後面
    }
    return L;
}
/*演算法2-2*/
void createLinkList2(LinkList *L)
{
    //L指向頭結點的指標的指標
    LNode *s;     //p指向尾結點, s指向新結點
    *L=(LNode *) malloc(sizeof(LNode));  //申請空白結點, *L指向頭結點
    if (*L==NULL) exit(0);
    *L->next =NULL; //建立了頭結點
    for(i=26;i>=1;i--)
    { 
        s=(LNode *) malloc(sizeof(LNode));  //申請空白結點, s指向
        if (!s) exit(0);
        s->data=i+‘a’-1; //給s->data 賦值
        s->next=*L->next;
        *L->next =s; //s指向的結點插入頭結點的後面
    }
}

(2)單鏈表的查詢

思路:從頭指標開始逐一查詢

/*例3:單鏈表的查詢*/
LNode* GetElem_L2(LinkList L, ElemType x)
{
    //在帶頭結點的單鏈表L中 查詢元素值為x的結點,
    //若找到返回指向該結點的指標,否則返回NULL.
    LNode *p;
    p=L->next; //p指向首元結點
    while (p->data!=x && p)
    {
        p=p->next; //p指標後移
    }
    return p;
}

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


(3)單鏈表的插入

在單鏈表中第i個位置插入一個元素x的示意圖如下:

/*例4:單鏈表的插入*/
bool ListInsert_L(LinkList *L, int i, ElemType e)
{ 
    // L 為指向帶頭結點的單鏈表的頭指標的指標
    //在連結串列中第i 個結點之前插入新的元素 e
    LNode *p; int j;
    p = *L; j = 0;
    while (p && j < i-1)
    {
         p = p->next; ++j;
    } // 尋找第 i-1 個結點
    if (!p || j > i-1)
    {
        return false; // i 大於n+1或者小於1
    }
    s = (LinkList) malloc(sizeof(LNode)) ; // 生成新結點
    if ( s == NULL)
    {
        return false;
    }
    s->data = e;
    s->next = p->next; p->next = s; // 插入
    return true;
} // LinstInsert_L

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


(4)單鏈表的刪除

/* 刪除單鏈表 */
void deleteList(LNode *pHead)
{
    LNode *p1,*p2;
    p1 = pHead;//p1指向第一個結點
    while(p1->next != pHead)//當p1不指向頭結點時
    {
        p2 = p1->next;
        free(p1);//刪除第n個連結串列
        p1 = p2;
    }
    free(pHead);//刪除頭結點
}

演算法時間複雜度:O(n)