第3章 線(xiàn)性表

1、簡(jiǎn)介

  • 線(xiàn)性表的數(shù)據(jù)對(duì)象集合為 {a1报咳,a2侠讯,.....挖藏,an }暑刃,每個(gè)元素的類(lèi)型均為 DataType
  • 其中,除第一個(gè)元素 a1 外膜眠,每一個(gè)元素有且只有一個(gè)直接前驅(qū)元素岩臣,除最后一個(gè)元素 an 外溜嗜,每一個(gè)元素有且只有一個(gè)直接后繼元素
  • 數(shù)據(jù)元素之間的關(guān)系是一對(duì)一的關(guān)系

2、基本操作

InitList(*L)          初始化操作架谎,建立一個(gè)空的線(xiàn)性表L
ListEmpty(L)          若線(xiàn)性表為空炸宵,返回 true,否則返回 false
ClearList(*L)         將線(xiàn)性表清空
GetElem(L, i, *e)     將線(xiàn)性表 L 中的第 i 個(gè)位置元素值返回給 e
LocateElem(L, e)      在線(xiàn)性表 L 中查找給定值 e 相等的元素谷扣,如果查找成功土全,返回該元素在表中序號(hào)表示成功;
                         否則会涎,返回 0 表示失敗
ListInsert(*L, i, e)  在線(xiàn)性表 L 中的第 i 個(gè)位置插入新元素 e
ListDelete(*L, i, *e) 刪除線(xiàn)性表 L 中第 i 個(gè)位置元素裹匙,并用 e 返回其值
ListLength(L)         返回線(xiàn)性表 L 中的元素個(gè)數(shù)

3、存儲(chǔ)結(jié)構(gòu)

3.1末秃、順序存儲(chǔ)結(jié)構(gòu)
  • 用一段地址連續(xù)的存儲(chǔ)單元依次存儲(chǔ)線(xiàn)性表的數(shù)據(jù)元素 (用一維數(shù)組來(lái)實(shí)現(xiàn))
  • 線(xiàn)性表順序存儲(chǔ)結(jié)構(gòu)代碼如下

#define MAXSIZE 20               // 存儲(chǔ)空間初始分配量
typedef int ElemType;            // ElemType 類(lèi)型根據(jù)實(shí)際情況而定概页,這里假設(shè)為 int 
typedef struct{                  
    ElemType data[MAXSIZE];      // 數(shù)組存儲(chǔ)數(shù)據(jù)元素,最大值 MAXSIZE
    int length;                  // 線(xiàn)性表當(dāng)前長(zhǎng)度
}SqList;
  • 獲取元素
    將線(xiàn)性表 L 中的第 i 個(gè)位置元素值返回給 e
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;

/* 初始條件:順序線(xiàn)性表L已存在练慕,1≤i≤ListLength(L) */
/* 操作結(jié)果:用e返回L中第i個(gè)數(shù)據(jù)元素的值,注意i是指位置惰匙,第1個(gè)位置的數(shù)組是從0開(kāi)始 */
Status GetElem(SqList L,int i,ElemType *e)
{
    if(L.length==0 || i<1 || i>L.length)
          return ERROR;
    *e=L.data[i-1];

    return OK;
}
  • 插入元素
    在線(xiàn)性表 L 中的第 i 個(gè)位置插入新元素 e
/* 初始條件:順序線(xiàn)性表L已存在,1≤i≤ListLength(L), */
/* 操作結(jié)果:在L中第i個(gè)位置之前插入新的數(shù)據(jù)元素e铃将,L的長(zhǎng)度加1 */
Status ListInsert(SqList *L,int i,ElemType e)
{ 
    int k;
    if (L->length == MAXSIZE)  /* 順序線(xiàn)性表已經(jīng)滿(mǎn) */
        return ERROR;
    if (i<1 || i > L->length+1)/* 當(dāng)i比第一位置小或者比最后一位置后一位置還要大時(shí) */
        return ERROR;

    if (i <= L->length)        /* 若插入數(shù)據(jù)位置不在表尾 */
    {
        for(k = L-> length; k >= i;k--)  /* 將要插入位置之后的數(shù)據(jù)元素向后移動(dòng)一位 */
            L->data[k] = L->data[k - 1];
    }
    L->data[i-1]=e;          /* 將新元素插入 */
    L->length++;

    return OK;
}
  • 刪除元素
    刪除線(xiàn)性表 L 中第 i 個(gè)位置元素项鬼,并用 e 返回其值
/* 初始條件:順序線(xiàn)性表L已存在,1≤i≤ListLength(L) */
/* 操作結(jié)果:刪除L的第i個(gè)數(shù)據(jù)元素劲阎,并用e返回其值秃臣,L的長(zhǎng)度減1 */
Status ListDelete(SqList *L,int i,ElemType *e) 
{ 
    int k;
    if (L->length == 0)               /* 線(xiàn)性表為空 */
        return ERROR;
    if (i<1 || i>L->length)         /* 刪除位置不正確 */
        return ERROR;
    *e = L->data[i-1];
    if (i < L->length)                /* 如果刪除不是最后位置 */
    {
        for(k = i-1; k < L->length-1; k++)/* 將刪除位置后繼元素前移 */
            L->data[k]=L->data[k+1];
    }
    L->length--;
    return OK;
}
  • 總結(jié)
    優(yōu)點(diǎn):1、無(wú)須為表示表中元素之間的邏輯關(guān)系而增加額外的存儲(chǔ)空間
       2哪工、可以快速地存取表中任一位置的元素
    缺點(diǎn):1奥此、插入和刪除操作需要移動(dòng)大量的元素
       2雁比、當(dāng)線(xiàn)性表長(zhǎng)度變化較大時(shí)稚虎,難以確定存儲(chǔ)空間的容量
       3偎捎、造成存儲(chǔ)空間的 "碎片"
3.2蠢终、鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)
  • 如下圖所示,如同一條鏈子一樣存儲(chǔ)信息
  • 為了表示每個(gè)數(shù)據(jù)元素 ai 與其直接后繼數(shù)據(jù)元素 ai+1 之間的邏輯關(guān)系茴她,對(duì)數(shù)據(jù)元素 ai 來(lái)說(shuō)寻拂,除了存儲(chǔ)其本身的信息之外,還需存儲(chǔ)一個(gè)指示其直接后繼的信息(即直接后繼的存儲(chǔ)位置)丈牢。
    我們把存儲(chǔ)數(shù)據(jù)元素信息的域稱(chēng)為數(shù)據(jù)域祭钉,把存儲(chǔ)直接后繼位置的域稱(chēng)為指針域
    指針域中存儲(chǔ)的信息稱(chēng)為指針或鏈己沛。這兩部分信息組成數(shù)據(jù)元素 a1 的存儲(chǔ)映像慌核,稱(chēng)為節(jié)點(diǎn) (Node)
  • 頭指針與頭結(jié)點(diǎn)的異同
    頭指針:
    1距境、頭指針是指鏈表指向第一個(gè)結(jié)點(diǎn)的指針,若鏈表有頭結(jié)點(diǎn)垮卓,則是指向頭結(jié)點(diǎn)的指針
    2垫桂、頭指針具有標(biāo)識(shí)作用,所以常用頭指針冠以鏈表的名字
    頭結(jié)點(diǎn):
    1粟按、頭結(jié)點(diǎn)是為了操作統(tǒng)一和方便而設(shè)立的诬滩,放在第一元素的結(jié)點(diǎn)之前,其數(shù)據(jù)域一般無(wú)意義(也可存放鏈表的長(zhǎng)度)
    2灭将、有了頭結(jié)點(diǎn)碱呼,對(duì)在第一元素結(jié)點(diǎn)前插入結(jié)點(diǎn)和刪除第一結(jié)點(diǎn),其操作與其它結(jié)點(diǎn)的操作就統(tǒng)一了
    3宗侦、頭結(jié)點(diǎn)不一定是鏈表必須要素
  • 單鏈表存儲(chǔ)結(jié)構(gòu)
typedef int ElemType;        /* ElemType類(lèi)型根據(jù)實(shí)際情況而定愚臀,這里假設(shè)為int */

typedef struct Node{
    ElemType data;
    struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定義LinkList */
  • 單鏈表的讀取
/* 初始條件:順序線(xiàn)性表L已存在,1≤i≤ListLength(L) */
/* 操作結(jié)果:用e返回L中第i個(gè)數(shù)據(jù)元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
    int j;
    LinkList p;         /* 聲明一結(jié)點(diǎn) p */
    p = L->next;        /* 讓 p 指向鏈表 L 的第一個(gè)結(jié)點(diǎn) */
    j = 1;              /* j 為計(jì)數(shù)器 */
    while (p && j<i)    /* p 不為空或者計(jì)數(shù)器 j 還沒(méi)有等于 i 時(shí)矾利,循環(huán)繼續(xù) */
    {   
        p = p->next;    /* 讓 p 指向下一個(gè)結(jié)點(diǎn) */
        ++j;
    }
    if ( !p || j>i ) 
        return ERROR;   /* 第 i 個(gè)元素不存在 */
    *e = p->data;       /* 取第 i 個(gè)元素的數(shù)據(jù) */
    return OK;
}
  • 單鏈表的插入
/* 初始條件:順序線(xiàn)性表 L 已存在,1 ≤ i ≤ ListLength(L) */
/* 操作結(jié)果:在 L 中第 i 個(gè)位置之前插入新的數(shù)據(jù)元素 e姑裂,L 的長(zhǎng)度加 1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{ 
    int j;
    LinkList p,s;
    p = *L;   
    j = 1;
    while (p && j < i)     /* 尋找第i個(gè)結(jié)點(diǎn) */
    {
        p = p->next;
        ++j;
    } 
    if (!p || j > i) 
        return ERROR;     /* 第i個(gè)元素不存在 */
    s = (LinkList)malloc(sizeof(Node));  /*  生成新結(jié)點(diǎn)(C語(yǔ)言標(biāo)準(zhǔn)函數(shù)) */
    s->data = e;  
    s->next = p->next;    /* 將p的后繼結(jié)點(diǎn)賦值給s的后繼  */
    p->next = s;          /* 將s賦值給p的后繼 */
    return OK;
}
  • 單鏈表的刪除
/* 初始條件:順序線(xiàn)性表 L 已存在,1 ≤ i ≤ ListLength(L) */
/* 操作結(jié)果:刪除L的第 i 個(gè)數(shù)據(jù)元素男旗,并用 e 返回其值舶斧,L 的長(zhǎng)度減 1 */
Status ListDelete(LinkList *L, int i, ElemType *e) 
{ 
    int j;
    LinkList p, q;
    p = *L;
    j = 1;
    while (p->next && j < i)    /* 遍歷尋找第 i 個(gè)元素 */
    {
        p = p->next;
        ++j;
    }
    if (!(p->next) || j > i) 
        return ERROR;           /* 第i個(gè)元素不存在 */
    q = p->next;
    p->next = q->next;          /* 將q的后繼賦值給p的后繼 */
    *e = q->data;               /* 將q結(jié)點(diǎn)中的數(shù)據(jù)給e */
    free(q);                    /* 讓系統(tǒng)回收此結(jié)點(diǎn),釋放內(nèi)存 */
    return OK;
}
  • 單鏈表的整表創(chuàng)建
    頭插法
/*  隨機(jī)產(chǎn)生n個(gè)元素的值察皇,建立帶表頭結(jié)點(diǎn)的單鏈線(xiàn)性表L(頭插法) */
void CreateListHead(LinkList *L, int n) 
{
    LinkList p;
    int i;
    srand(time(0));                         /* 初始化隨機(jī)數(shù)種子 */
    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;                      /*  先建立一個(gè)帶頭結(jié)點(diǎn)的單鏈表 */
    for (i=0; i<n; i++) 
    {
        p = (LinkList)malloc(sizeof(Node)); /*  生成新結(jié)點(diǎn) */
        p->data = rand()%100+1;             /*  隨機(jī)生成100以?xún)?nèi)的數(shù)字 */
        p->next = (*L)->next;    
        (*L)->next = p;                     /*  插入到表頭 */
    }
}

尾插法

/*  隨機(jī)產(chǎn)生n個(gè)元素的值茴厉,建立帶表頭結(jié)點(diǎn)的單鏈線(xiàn)性表L(尾插法) */
void CreateListTail(LinkList *L, int n) 
{
    LinkList p,r;
    int i;
    srand(time(0));                      /* 初始化隨機(jī)數(shù)種子 */
    *L = (LinkList)malloc(sizeof(Node)); /* L為整個(gè)線(xiàn)性表 */
    r=*L;                                /* r為指向尾部的結(jié)點(diǎn) */
    for (i=0; i<n; i++) 
    {
        p = (Node *)malloc(sizeof(Node)); /*  生成新結(jié)點(diǎn) */
        p->data = rand()%100+1;           /*  隨機(jī)生成100以?xún)?nèi)的數(shù)字 */
        r->next=p;                        /* 將表尾終端結(jié)點(diǎn)的指針指向新結(jié)點(diǎn) */
        r = p;                            /* 將當(dāng)前的新結(jié)點(diǎn)定義為表尾終端結(jié)點(diǎn) */
    }
    r->next = NULL;                       /* 表示當(dāng)前鏈表結(jié)束 */
}
  • 單鏈表的整表刪除
/* 初始條件:順序線(xiàn)性表L已存在。操作結(jié)果:將L重置為空表 */
Status ClearList(LinkList *L)
{ 
    LinkList p,q;
    p=(*L)->next;           /*  p指向第一個(gè)結(jié)點(diǎn) */
    while(p)                /*  沒(méi)到表尾 */
    {
        q=p->next;
        free(p);
        p=q;
    }
    (*L)->next=NULL;        /* 頭結(jié)點(diǎn)指針域?yàn)榭?*/
    return OK;
}
  • 單鏈表結(jié)構(gòu)與順序存儲(chǔ)結(jié)構(gòu)優(yōu)缺點(diǎn)
    存儲(chǔ)分配方式: 1什荣、順序存儲(chǔ)結(jié)構(gòu)用一段連續(xù)的存儲(chǔ)單元依次存儲(chǔ)線(xiàn)性表的數(shù)據(jù)元素
    2矾缓、單鏈表采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),用一組任意的存儲(chǔ)單元存放線(xiàn)性表的元素

時(shí)間性能: 1稻爬、查找: 順序存儲(chǔ)結(jié)構(gòu)O(1)嗜闻; 單鏈表O(n)
2、插入和刪除: 順序存儲(chǔ)結(jié)構(gòu)需要平均移動(dòng)表長(zhǎng)一半的元素桅锄,時(shí)間O(n)琉雳;
單鏈表在找出某位置的指針后,插入和刪除時(shí)間僅為O(1)

空間性能: 1友瘤、順序存儲(chǔ)結(jié)構(gòu)需要預(yù)分配存儲(chǔ)空間翠肘,分大了,浪費(fèi)辫秧;分小了束倍,易發(fā)生浪費(fèi)
2、單鏈表不需要分配存儲(chǔ)空間,只要有就可以分配肌幽,元素個(gè)數(shù)也不受限制

  • 經(jīng)驗(yàn)性結(jié)論
    若線(xiàn)性表需要頻繁查找,很少進(jìn)行插入和刪除操作時(shí)抓半,宜采用順序存儲(chǔ)結(jié)構(gòu)喂急。
    若需要頻繁插入和刪除時(shí),宜采用單鏈表結(jié)構(gòu)

4笛求、靜態(tài)鏈表

用數(shù)組來(lái)代替指針廊移,來(lái)描述單鏈表。
我們把這種用數(shù)組描述的鏈表叫做靜態(tài)鏈表
優(yōu)點(diǎn): 在插入和刪除操作時(shí)探入,只需要修改游標(biāo)狡孔,不需要移動(dòng)元素,從而改進(jìn)了在順序存儲(chǔ)結(jié)構(gòu)中的插入和刪除操作需要移動(dòng)大量元素的缺點(diǎn)
缺點(diǎn): 沒(méi)有解決連續(xù)存儲(chǔ)分配帶來(lái)的表長(zhǎng)難以確定的問(wèn)題蜂嗽;失去了順序存儲(chǔ)結(jié)構(gòu)隨機(jī)存取的特性

5苗膝、循環(huán)鏈表

將單鏈表中終端結(jié)點(diǎn)的指針端由空指針改為指向頭結(jié)點(diǎn),就使整個(gè)單鏈表形成一個(gè)環(huán)植旧,這種頭尾相接的單鏈表稱(chēng)為單循環(huán)鏈表辱揭,簡(jiǎn)稱(chēng)循環(huán)鏈表

6、雙向鏈表

雙向鏈表是在單鏈表的每個(gè)結(jié)點(diǎn)中病附,再設(shè)置一個(gè)指向其前驅(qū)結(jié)點(diǎn)的指針域问窃。
所以在雙向鏈表中的結(jié)點(diǎn)都有兩個(gè)指針域,一個(gè)指向直接后繼完沪,另一個(gè)指向直接前驅(qū)域庇。


線(xiàn)性表結(jié)構(gòu)圖解
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市覆积,隨后出現(xiàn)的幾起案子听皿,更是在濱河造成了極大的恐慌,老刑警劉巖宽档,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件写穴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雌贱,警方通過(guò)查閱死者的電腦和手機(jī)啊送,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)欣孤,“玉大人馋没,你說(shuō)我怎么就攤上這事〗荡” “怎么了篷朵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我声旺,道長(zhǎng)笔链,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任腮猖,我火速辦了婚禮鉴扫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘澈缺。我一直安慰自己坪创,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布姐赡。 她就那樣靜靜地躺著莱预,像睡著了一般。 火紅的嫁衣襯著肌膚如雪项滑。 梳的紋絲不亂的頭發(fā)上依沮,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音枪狂,去河邊找鬼悉抵。 笑死,一個(gè)胖子當(dāng)著我的面吹牛摘完,可吹牛的內(nèi)容都是我干的姥饰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼孝治,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼列粪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起谈飒,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岂座,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后杭措,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體费什,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年手素,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸳址。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泉懦,死狀恐怖稿黍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情崩哩,我是刑警寧澤巡球,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布言沐,位于F島的核電站,受9級(jí)特大地震影響酣栈,放射性物質(zhì)發(fā)生泄漏险胰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一矿筝、第九天 我趴在偏房一處隱蔽的房頂上張望起便。 院中可真熱鬧,春花似錦跋涣、人聲如沸缨睡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至细诸,卻和暖如春沛贪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背震贵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猩系,地道東北人媚送。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像塘偎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容