1. 程式人生 > >靜態連結串列基礎

靜態連結串列基礎

靜態連結串列

在沒有指標和類的早期程式語言(如Basic、Fortran等語言),為了實現連結串列,有人想到了拿陣列來代替指標,來描述單鏈表。

首先,我們讓陣列的元素都是由兩個資料域組成,data和cur,也就說,陣列的每個下標都對應了一個data和cur,而cur相當於單鏈表中的next指標,
存放該元素後繼在陣列中的下標,我們把cur叫做遊標。我們把上述這種陣列描述的連結串列叫做靜態連結串列,這種描述方法叫做遊標實現法

為了方便我們插入資料,我們通常會把陣列建立的大一些,以便有一些空閒空間以至於插入時不會溢位。另外,我們對陣列第一個和最後一個元素作為特殊元素處理,不存資料,我們通常把未被使用的陣列元素稱為備用連結串列

陣列的第一個元素,即下標為0的元素的cur就存放備用連結串列的第一個結點的下標;而陣列的最後一個元素的cur則存放第一個有數值元素的下標,相當於單鏈表的頭結點作用。


靜態連結串列的結構

typedef struct {
    ElemType data; //資料域
    int cur; //遊標
}Component, StaticLinkList[MAXSIZE];

初始化靜態連結串列

bool InitList(StaticLinkList & sapce)
{
    for(int i = 0; i < MAXN - 1; ++i)
        space[i].cur = i + 1;
    space[MAXN - 1].cur = 0; //目前靜態連結串列為空,最後一個元素的cur為0
    return true;
}

靜態連結串列的插入操作

靜態連結串列中要解決的是:如何用靜態模擬動態連結串列結構的儲存空間的分配,需要時申請,無用時釋放。

在動態連結串列中,結點申請和是否別分借用malloc()free()兩個函式來實現,在靜態連結串列中,操作的是陣列,不存在像動態連結串列中的結點申請和釋放問題,所以我們需要自己實現這兩個函式。

為了辨明陣列中那些分量未被使用,解決的辦法是將所有未被使用過的及已被刪除的分量用遊標鏈成一個備用的連結串列,每當進行插入時,便可以從備用連結串列上取得第一個結點作為待插入的新節點。

手動實現Malloc_SLL()函式:

/*若備用空間連結串列非空,則返回分配的結點下標,否則返回0*/
int Malloc_SLL(StaticLinkList &space)
{
    int i = space[0].cur;  //當前陣列第一個元素的cur存的值就是要返回的一個備用空閒下標
    if(i)
        space[0].cur = space[i].cur; //由於要拿出一個分量來使用,我們要把下一個分量拿來做備用。
    return i;
}

靜態連結串列的插入

在第i個位置插入新的元素e:

bool ListInsert(StaticLinkList &L, int i, ElemType e)
{
    int k = MAXN - 1; //k是最後一個元素的下標
    if(i < 1 || i > ListLength(L) + 1) return false;  //插入位置非法
    int j = Malloc_SLL(L);  //分配一個空閒下標
    if(j) {
        L[j].data = e; //將資料賦值給此分量的data域
        for(int p = 1; p <= i - 1; ++p)  //找到第i個元素之前的位置
            k = L[k].cur; 
        L[j].cur = L[k].cur;  //把第i個元素之前的cur賦值給
        L[k].cur = j;   //把新元素的下標賦值給第i個元素之前元素的cur
        return true;
    }
    return false;
}

靜態連結串列的刪除

手動實現Free_SLL()函式:

void Free_SLL(StaticLinkList &space, int k)
{
    space[k].cur = space[0].cur; //把第一個元素cur值賦值給要刪除的分量cur
    space[0].cur = k;  //把要刪除的分量下標賦值給第一個元素的cur
}

刪除靜態連結串列第i個元素的演算法:

bool ListDetele(StaticLinkList &L, int i)
{
    int k, j;
    if(i < 1 || i > ListLength(L)) return false;
    int k = MAXN - 1;
    for(j = 1; j <= i - 1; ++j) //找到要刪除結點的前驅
        k = L[k].cur;
    j = L[k].cur; // 要刪除的結點
    L[k].cur = L[j].cur; //讓要刪除結點的前驅指向刪除結點的後繼。
    Free_SLL(L, j); //刪除第j個位置的結點

    return true;
}

總結

靜態連結串列的優點: 在插入和刪除操作時,只需要修改遊標,不需要移動元素,從而改進了在順序儲存結構中的插入和刪除操作需要移動大量元素的缺點。

靜態連結串列的缺點: 沒有解決連續分配記憶體帶來的表長難以確定的問題,失去了順序儲存結構隨機存取的特性。

總的來說,靜態連結串列是為了給沒有指標和類的高階語言設計的一種實現單鏈表能力的方法,儘管很難用到,但應理解其思想,以備不時之需。