1. 程式人生 > >HNCU1327:演算法2-13~2-16:靜態連結串列

HNCU1327:演算法2-13~2-16:靜態連結串列

題目描述

靜態連結串列是使用順序儲存結構來實現的連結串列。嚴蔚敏《資料結構(C語言版)》在介紹靜態連結串列時使用的是一個姓氏列表。 圖1是書本上的靜態連結串列示例,圖(a)是初始化後插入了8個姓氏的連結串列,圖(b)是在第5個元素前插入了“SHI”而刪除了“WANG”的結果。 圖1:靜態連結串列示例 (a)修改前的狀態;(b)修改後的狀態 現在,我們就來實現一下這個靜態連結串列。實際上靜態連結串列與一般含有指標的連結串列沒有太大的差別,只是靜態連結串列的結點存放的空間不是在使用時臨時分配的,而是在一開始就分配了固定的一些,一般是用陣列。同時一般的連結串列使用指標來指向下一個結點而在靜態連結串列中則使用陣列下標了。大家如果看嚴蔚敏的書會發現書上的演算法還是有些問題的。下面我就直接給大家展示一種靜態連結串列的實現演算法。 最重要的是模擬系統分配記憶體的過程。可以預先定義一個全域性陣列(space)作為後面分配的空間,然後再初始化這個陣列,為以後分配做準備,如圖2。初始化後,這個陣列中的狀態應該如圖3(a)一樣。這樣,陣列的第0個節點就是用來標識哪個結點可用來儲存資料的。那麼如果是含有頭結點的靜態連結串列,則一般開始時陣列的第1個節點就是用來存放頭結點的,此時陣列第0個結點標識第2個結點可以用來儲存資料,而第1個結點(靜態連結串列的頭結點)的下一個結點下標為0,標識著這個靜態連結串列為空,如圖3(b)。靜態連結串列的初始化以及插入刪除各種演算法與一般的連結串列是相似的。具體描述如下:
圖2:型別定義、用來模擬記憶體的陣列定義以及初始化 圖3:模擬記憶體的陣列狀態。(a)初始化後的狀態,(b)給靜態連結串列分配頭結點後的狀態 圖4:在靜態連結串列中查詢元素在space中的位置(相當於地址) 圖5:給靜態連結串列中的結點分配儲存空間,實際上返回的是陣列中可用的結點下標 圖6:釋放靜態連結串列中結點的儲存空間

輸入格式

靜態連結串列的儲存空間(圖2中的space)始終只有11個節點,起始為空表。insert a e代表在第a個姓氏前插入姓氏edelete a代表刪除第a個姓氏;search e代表查詢姓氏e的位置;show代表輸出靜態連結串列儲存空間的狀態。輸入保證操作都合法。

輸出

只遇到searchshow時才輸出。當遇到search時輸出姓氏espace中的位置;當遇到show時輸出這11個結點的狀態。姓氏佔8個字元而數字佔2個字元,姓氏左對齊。每個指令輸出後面跟著含有20個星號的行。

樣例輸入

show
insert 1 ZHAO
show
insert 2 QIAN
show
insert 3 SUN
show
insert 4 LI
insert 5 ZHOU
insert 6 WU
insert 7 ZHENG
insert 8 WANG
show
insert 1 ZHANG
show
search LI
show

樣例輸出

         2
         0
         3
         4
         5
         6
         7
         8
         9
        10
         0
********************
         3
         2
ZHAO     0
         4
         5
         6
         7
         8
         9
        10
         0
********************
         4
         2
ZHAO     3
QIAN     0
         5
         6
         7
         8
         9
        10
         0
********************
         5
         2
ZHAO     3
QIAN     4
SUN      0
         6
         7
         8
         9
        10
         0
********************
        10
         2
ZHAO     3
QIAN     4
SUN      5
LI       6
ZHOU     7
WU       8
ZHENG    9
WANG     0
         0
********************
         0
        10
ZHAO     3
QIAN     4
SUN      5
LI       6
ZHOU     7
WU       8
ZHENG    9
WANG     0
ZHANG    2
********************
 5
********************
         0
        10
ZHAO     3
QIAN     4
SUN      5
LI       6
ZHOU     7
WU       8
ZHENG    9
WANG     0
ZHANG    2
********************

#include <stdio.h>
#include <string.h>

#define MAXSIZE 11                        // 靜態連結串列的長度
typedef char ElemType[8];        // 元素的型別,規定姓氏不超過7個字元

typedef struct
{
    ElemType data;                        // 節點中的資料
    int cur;                                // 下一個節點的下標(相當於指標)
} NodeType;                                       // 節點型別

NodeType space[MAXSIZE];        // 用來儲存節點的陣列,相當於一般連結串列中的記憶體,
// 只是那個記憶體是系統分配的,我們看不到

typedef struct
{
    int elem;                                // 靜態連結串列儲存空間基址(起始元素的下標)
    int length;                                // 靜態連結串列中的元素數目
    int listSize;                        // 靜態連結串列當前的長度,可容納元素數目
} SLinkList;                                       // 靜態連結串列型別的定義,和一般的連結串列類似

int LocateElem_SL(SLinkList& S, ElemType e)
{
    // 在靜態單鏈線性表L中查詢第1個值為e的元素。
    // 若找到,則返回它在L中的位序,否則返回0。
    int i;
    i = S.elem; // i指示表中第一個結點
    while (i && strcmp(space[i].data, e))
        i = space[i].cur; // 在表中順鏈查詢
    return i;
}

void InitSpace_SL()
{
    // 將一維陣列space中各分量鏈成一個備用連結串列,space[0].cur為頭指標,
    // "0"表示空指標
    memset(space, 0 ,sizeof(space));
    for (int i = 0; i < MAXSIZE - 1; ++i)
        space[i].cur = i + 1;
    space[MAXSIZE - 1].cur = 0;
}

int Malloc_SL()
{
    /* 若備用連結串列非空,則返回分配的結點下標(備用連結串列的第一個結點),否則返回0 */
    int i = space[0].cur;
    if (i) /* 備用連結串列非空 */
        space[0].cur = space[i].cur;/* 備用連結串列的頭結點指向原備用連結串列的第二個結點 */
    return i;/* 返回新開闢結點的座標 */
}

void Free_SL(int k)
{/* 將下標為k的空閒結點回收到備用連結串列(成為備用連結串列的第一個結點) */
    space[k].cur = space[0].cur;/* 回收結點的"遊標"指向備用連結串列的第一個結點 */
    space[0].cur = k; /* 備用連結串列的頭結點指向新回收的結點 */
}

void Insert_SL(SLinkList& S, int i, ElemType e)
{
    // 往靜態連結串列S中的第 i 個位置前插入e
    int cur = S.elem;                // 指向靜態連結串列中的第一個節點
    int j=0;
    int newNodeIndex;                // 儲存新分配的節點下標
    while(j < i-1)                         // 尋找第 i-1 個節點
    {
        cur = space[cur].cur;
        ++j;
    }
    newNodeIndex = Malloc_SL();        // 分配新的節點
    strcpy(space[newNodeIndex].data,e);        // 在新的節點中存入資料
    space[newNodeIndex].cur = 0;                // 指標為空,這一點很重要
    space[newNodeIndex].cur = space[cur].cur;        // 插入靜態連結串列中
    space[cur].cur = newNodeIndex;
    S.length++;                        // 插入後靜態連結串列長度加1
}

void Delete_SL(SLinkList& S, int i)
{
    // 刪除靜態連結串列中的第 i 個節點
    int cur = S.elem;                // 指向靜態連結串列中的第一個節點
    int j=0;
    int delCur;                                // 儲存待刪除節點的下標
    while(j < i-1)                         // 尋找第 i-1 個節點
    {
        cur = space[cur].cur;
        ++j;
    }
    delCur = space[cur].cur;                // 找到待刪除節點的下標
    space[cur].cur = space[delCur].cur;        // 刪除節點
    Free_SL(delCur);                        // 釋放節點
    S.length--;                        // 刪除後靜態連結串列長度減1
}

void CreateList_SL(SLinkList& S)         // 建立靜態連結串列
{
    S.elem = Malloc_SL();                        // 分配頭結點的指標
    space[S.elem].cur = 0;
    S.length = 0;
    S.listSize = 9;
}

void Show_space()
{
    // 將靜態連結串列中所有的節點顯示出來
    int i;
    for(i=0; i<MAXSIZE; i++)
    {
        printf("%-8s%2d\n", space[i].data, space[i].cur);
    }
}

int main()
{

    SLinkList S;                // 定義靜態連結串列
    char str[10];                // 用來獲得指令
    int a;                                // 儲存位置
    ElemType e;                        // 儲存元素
    InitSpace_SL();                // 初始化備用連結串列
    CreateList_SL(S);        // 建立靜態連結串列
    while(scanf("%s", str) != EOF)
    {
        if(strcmp(str, "insert") == 0)                         // 插入元素
        {
            scanf("%d%s", &a, e);
            Insert_SL(S, a, e);
        }
        else if(strcmp(str, "delete") == 0)          // 刪除元素
        {
            scanf("%d", &a);
            Delete_SL(S, a);
        }
        else if(strcmp(str, "search") == 0)          // 搜尋元素
        {
            scanf("%s", e);
            printf("%2d\n********************\n", LocateElem_SL(S, e));
        }
        else if(strcmp(str, "show") == 0)                  // 顯示靜態連結串列狀態
        {
            Show_space();
            puts("********************");                                                // 注意空一行
        }
    }

    return 0;
}