數據結構03-線性表之順序表

第三章 線性表之順序表

  • 第三章 線性表之順序表
    • 一、什么是線性表?
      • 1> 概念
      • 2> 線性表的基本操作
    • 二、線性表的順序存儲
        1. 存儲結構
        • 順序存儲圖示
        1. 核心操作
        • 1> 初始化
          • 順序表初始化圖示
          • C 語言實現
        • 2> 清空
          • 順序表清空圖示
          • C 語言實現
        • 3> 銷毀
          • 順序表銷毀圖示
          • C 語言實現
        • 4> 插入
          • 順序表插入圖示
          • C 語言實現
        • 5> 刪除
          • 順序表刪除圖示
          • C 語言實現
        • 6> 隨機訪問
          • C 語言實現
        1. 總結

一、什么是線性表?

1> 概念

線性表: n 個元素的有序序列。n 可為 0,表示空表;n > 0 時,除了頭元素,每個元素都有后繼元素,除了尾元素,每個元素都有前驅元素。換句俗話,就是說線性表中有 n 個元素,它們按順序串成一串兒。

線性表的特點:

  1. 同一性:線性表的元素都屬于同一類型;
  2. 有窮性:線性表由有限個數據元素組成,表長度就是表中數據元素的個數;
  3. 有序性:線性表中元素有序。

2> 線性表的基本操作

線性表的抽象數據型規定了線性表的基本操作,它們相當于線性表的接口。基本操作只考慮功能,不考慮實現;不同的存儲方式下,實現相同的功能算法也不同;后續我們將采用不同的存儲方式實現這些基本操作。

  1. InitList(&L)
    • 結果:構造一個空的線性表 L
  2. DestroyList(&L)
    • 前提:線性表 L 已存在
    • 結果:將 L 銷毀
  3. ClearList(&L)
    • 前提:線性表 L 已存在
    • 結果:將 L 置為空表
  4. EmptyList(&L)
    • 前提:線性表 L 已存在
    • 結果:如果 L 為空表,則返回 TRUE,否則,返回 FALSE
  5. ListLength(L)
    • 前提:線性表 L 已存在
    • 結果:返回表中的元素個數
  6. GetElem(L, i, &e)
    • 前提:表 L 存在,且 0 <= i <= ListLength(L) - 1
    • 結果:用 e 返回 L 中第 i 個數據元素
  7. LocateElem(L, e, compare())
    • 前提:表 L 存在,compare 是數據元素的判定函數
    • 結果:返回 L 中第 1 個與 e 滿足關系 compare() 的數據元素的位序,如果 e 不存在,在返回 0
  8. PriorElem(L, cur_e, &pre_e)
    • 前提:線性表已存在
    • 結果:若 cur_e 是 L 的數據元素,且不是第一個,則用 pre_e 返回它的前驅,否則操作失敗,pre_e 無定義
  9. NextElem(L, cur_e, &next_e)
    • 前提:線性表已存在
    • 結果:若 cur_e 是 L 的數據元素,且不是最后一個,則用 next_e 返回它的前驅,否則操作失敗,next_e 無定義
  10. ListInsert(&L, i, e)
    • 前提:表 L 已存在,e 為合法元素值且 0 <= i <= ListLength(L)
    • 結果:在 L 中第 i 個位置之前插入新的數據 e,L 的長度加 1
  11. ListDelete(&L, i, &e)
    • 前提:表 L 存在且非空,0 <= i <= ListLength(L) - 1
    • 結果:刪除 L 的第 i 個數據元素,并用 e 返回其值,L 的長度減 1
  12. ListTranverse(L, visit())
    • 前提:表 L 存在
    • 結果:依次對 L 的每個數據元素調用 visit(),一旦 visit() 失敗則操作失敗

二、線性表的順序存儲

線性表的順序存儲 是指用一組地址連續的存儲單元存儲數據,使得邏輯上相鄰的元素在物理上也是相鄰的。

1. 存儲結構

我們可以使用一維數組來存儲一個線性表的元素,具體如下:

// 緩沖區初始大小
#define LIST_INIT_SIZE  100
// 緩沖區增量
#define LIST_INCREMENT  10
// 順序表結構
typedef struct
{
    char    *elem;     // 線性表存儲空間基址,為簡便起見,我們讓線性表存儲單個字符
    int     length;    // 線性表中元素個數
    int     listsize;  // 當前分配的存儲容量
} SeqList;

順序存儲圖示

順序表

2. 核心操作

我們詳細說明順序表的核心操作,其他操作見項目代碼。

1> 初始化

申請順序表空間,初始化變量。

順序表初始化圖示
順序表初始化
C 語言實現
// 前提:L 為未初始化的線性表
// 結果:將 L 初始化為空表
Status    InitList(SeqList& L)
{   // 開辟順序表的初始存儲空間,即:緩沖區空間
    L.elem = (char*) malloc(LIST_INIT_SIZE * sizeof(char));
    if(!L.elem)
    { // 如果申請失敗,返回錯誤代碼
        printf("存儲分配失敗\n");
        return OVERFLOW;
    }
    L.length = 0;                 // 設置元素個數為 0
    L.listsize = LIST_INIT_SIZE;  // 設置初始緩沖區大小
    return OK;                    // 初始化成功
}

2> 清空

將當前順序表中數據清除,保持原有存儲結構;此時緩沖區大小 L.listsize 不做改變,也就是說,緩沖區大小是可以大于初始大小 LIST_INIT_SIZE 的。

順序表清空圖示
順序表清空
C 語言實現
// 前提:線性表 L 已存在
// 結果:將 L 置為空表
void    ClearList(SeqList &L)
{
    // 將順序表緩沖區中的數據清零
    if(L.elem)
        memset(L.elem, 0, sizeof(char) * L.listsize);
    // 將順序表長度置 0
    L.length = 0;
}

3> 銷毀

將順序表銷毀,釋放所有占用的內存。

順序表銷毀圖示
順序表銷毀
C 語言實現
// 前提:線性表 L 已存在
// 結果:將 L 銷毀
void    DestroyList(SeqList &L)
{
    if(L.elem)
    {
        free(L.elem);
        L.elem = NULL;
    }
    L.length = 0;
    L.listsize = 0;
}

4> 插入

在順序表中的指定位置 i (0 <= i <= L.length) 插入元素 e。

順序表插入圖示
順序表插入
C 語言實現
// 前提:表 L 已存在,e 為合法元素值且 0 <= i <= ListLength(L)
// 結果:在 L 中第 i 個位置之前插入新的數據 e,L 的長度加 1,
//       插入成功返回 TRUE,否則,返回 FALSE
int ListInsert(SeqList &L, int i, char e)
{   // 判斷插入位置是否合法
    if(i < 0 || i > L.length)
        return ERROR; // 地址錯誤
    // 判斷緩沖區是否充足
    if(L.length >= L.listsize)
    {   // 緩存區長度不夠,擴大容量,讓緩沖區增加 LIST_INCREMENT
        char *buf = (char*) realloc(L.elem, (L.listsize + LIST_INCREMENT) * sizeof(char));
        if(!buf) return OVERFLOW;
        // 重置緩沖區指針
        L.elem = buf;
        // 重置緩沖區大小
        L.listsize += LIST_INCREMENT;
    }
    // pos 指向下標為 i 的元素
    char *pos = &(L.elem[i]);
    // p 從最后一個數據元素 L.elem[L.length - 1] 開始,依次遞減,直到下標為 i 的元素
    for(char *p = &(L.elem[L.length - 1]); p >= pos; p--)
        *(p + 1) = *p;  // 將當前元素向后移動一個位置
    *pos = e;     // 將新增元素放在 pos 所指位置
    L.length++;   // 元素個數加 1
    return OK;
}

5> 刪除

將順序表中指定位置的元素刪除。

順序表刪除圖示
順序表刪除
C 語言實現
// 刪除表中元素
// 前提:表 L 存在且非空,0 <= i <= ListLength(L) - 1
// 結果:刪除 L 的第 i 個數據元素,并用 e 返回其值,L 的長度減 1
int ListDelete(SeqList &L, int i, char &e)
{
    // 判斷刪除位置是否合法
    if(i < 0 || i >= L.length)  return ERROR;
    // p 指向下標為 i 的元素
    char *p = &L.elem[i];
    // 將下標為 i 的元素放入 e 以便返回
    e = *p;
    // 從 p + 1 開始,到 L.elem[L.length - 1],將每個元素向前移動一個位置
    for(p++; p < L.elem + L.length; p++)
        *(p - 1) = *p;
    L.length--; // 元素個數減 1

    return OK;
}

6> 隨機訪問

獲取線性表中指定位置 i (0 <= i <= L.length - 1) 的元素值。

C 語言實現
// 前提:表 L 存在,且 0 <= i <= ListLength(L) - 1
// 結果:用 e 返回 L 中第 i 個數據元素,
// 如果失敗,返回 ERROR;否則,返回 OK
int GetElem(SeqList &L, int i, char *e)
{   // 判斷位置是否合法
    if(i < 0 || i >= L.length)
        return ERROR;
    // 將下標為 i 的元素放入 e 以便返回
    *e = L.elem[i];
    return OK;
}

3. 總結

  1. 順序表隨機訪問時,效率比較高,直接就可以訪問到,時間為:O(1)
  2. 順序表插入和刪除時,為了保持順序結構,需要移動大量的元素,因此效率很差,時間復雜度為:O(n)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容