1. 線性結構--線性表

線性表

定義

由同類型數據元素構成有序序列的線性結構。

  • 表中元素個數稱爲線性表的長度
  • 線性表沒有元素時,稱爲空表
  • 表起始位置稱表頭,表結束位置稱表尾

抽象數據類型描述

  • 類型名稱:線性表(List)
  • 數據對象集:線性表是n(0) 個元素構成的有序序列(a1,a2,...,an)
  • 操作集:線性表LList ,整數i 表示位置,元素XElementType ,線性表的主要操作有:
    1. List MakeEmpty():初始化一個空線性表L
    2. ElementType FindKth(int K, List L):根據位序K,返回相應的元素
    3. int Find(ElementType X, List L):在線性表L中查找X第一次出現的位置
    4. void Insert(ElementType X, int i, ListL):在位序i前插入一個新元素X
    5. void Delete(int i, List L):刪除指定位序i的元素
    6. int Length(List L):返回線性表L的長度n

順序存儲實現

利用數組的連續存儲空間順序存放線性表的個元素。

線性表的代碼定義

typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    int Last;
};
struct LNode L;
List Ptrl;
  • 訪問下標爲i的元素:L.Data[[i]Ptrl->Data[i]
  • 線性表的長度:L.Last + 1Ptrl->Last + 1

主要操作的實現

初始化(建立空的順序表)

List MakeEmpty() {
    List PtrL;
    PtrL = (List)malloc(sizeof(struct LNode));
    PtrL-Last = -1;
    return PtrL;
}

查找

int Find(ElementType X, List PtrL) {
    int i = 0;
    while (i <= PtrL->Last && PtrL->Data[i] != X)
        i++;

    if (i > PtrL->Last) // 說明沒有找到,返回-1
        return -1;
    return i;           // 找到後返回的是存儲位置
}

查找成功的平均比較次數爲(n+1)/2 ,平均時間性能爲O(n)

插入

在第i(iin+1) 個位置插入一個值爲X的新元素
image

void Insert(ElementType X, int i, List PtrL) {
    int j;
    if (PtrL->Last == MAXSIZE - 1) {    // 表空間已滿,不能插入
        printf("表滿");
        return;
    }

    if (i < 1 || i > PtrL->Last + 2) { // 位置只能從第一個到末尾之間
        printf("位置不合法");
        return;
    }

    for (j = PtrL->Last; j >= i - 1; j--)   // 將ai ~ an倒序向後移動
        PtrL->Data[j + 1] = PtrL->Data[j] ; 

    PtrL->Data[i - 1] = X;                  // 新元素插入
    PtrL->Last++;                           // Last仍然指代最後元素的下標
}

元素的向後移動:
* 平均移動次數爲n/2
* 平均時間性能爲O(n)

刪除

刪除表的第i(1in) 個位置的元素
image

void Delete(int i, List PtrL) {
    int j;
    if (i < 1 || i > PtrL->Last + 1) {
        printf("不存在第%d個元素", i);
        return;
    }

    for (j = i; j <= PtrL->Last; j++)
        PtrL->Data[j - 1] = PtrL->Data[j];  // 將ai+1 ~ an 順序向前移動
    PtrL->Last--;                           // Last仍然指代最後元素的下標
}

鏈式存儲實現

不要求邏輯上相鄰的兩個元素物理上也相鄰。通過“鏈”建立起數據元素之間的邏輯關係。

線性表的代碼定義

typeof struct LNode *List;
struct LNode {
    ElementType Data;
    List Next;
};
struct LNode L;
List PtrL;

主要操作的實現

求表長

int Length(List PtrL) {
    List p = PtrL;      // p指向表的第一個結點
    int len = 0;
    while (p != NULL) {
        p = p->Next;
        len++;          // 當前P指向的是第len個結點
    }

    return len;
}

時間性能爲O(n)

查找

按序號查:FindKth
List FindKth(int K, List PtrL) {
    List p = PtrL;
    int i = 1;
    while (p != NULL && i < k) {
        p = p->Next;
        i++;
    }

    if (i == k)             // 說明找到第K個元素
        return P;

    return NULL;
}

平均時間性能爲O(n)

按值查找:Find
List Find(ElementType X, List PtrL) {
    List p = PtrL;
    while (p != NULL && p->Data != X)   // 如果在鏈表中沒有元素等於X,那麼會返回NULL
        p = p->Next;

    return p;
}

平均時間性能爲O(n)

插入

在第i1(1in+1) 個結點後插入一個值爲X的新結點:
1. 先構造一個新結點,用s指向
2. 再找到鏈表的第i1 個結點,用p指向
3. 然後修改指針,插入結點(p之後插入新結點是S)
image

// 不帶頭結點的鏈表
List Insert(ElementType X, int i, List PtrL) {
    List p, s;

    if (i == 1) {                               // 新結點插入在表頭
        s = (List)malloc(sizeof(struct LNode)); // 創建一個新結點
        s->Data = x;
        s->Next = PtrL;
        return s;
    }

    p = FindKth(i - 1, PtrL);   // 查找到第i-1個結點
    if (p == NULL) {            // 第i-1個不存在,不能插入
        printf("參數i錯誤");
        return NULL;
    }

    s = (List)malloc(sizeof(struct LNode)); // 創建一個新結點
    s->Data = x;
    s->Next = p->Next;                      // 新結點插入在第i-1個結點後面
    p->Next = s;
    return PtrL;
}

平均查找次數爲n/2 ,平均時間性能爲O(n)

刪除

刪除鏈表的第i(1in) 個位置的結點:
1. 先找到鏈表的第i1 個結點,用p指向
2. 再用指針s指向要被刪除的結點(p的下一個結點)
3. 然後修改指針,刪除s所指結點
4. 最後釋放s所指結點的空間

image

List Delete(int i, List PtrL) {
    List p, s;
    if (i == 1) {                   // 如果刪除的是表的第一個結點
        s = PtrL;                   // s指向第一個結點
        if (PtrL != NULL)           // 從鏈表中刪除
            PtrL = PtrL->Next;
        else 
            return NULL;
        free(s);
        return PtrL;
    }

    p = FindKth(i - 1, PtrL);       // 查找第i-1個結點
    if (P == NULL || p->Next == NULL) {
        printf("第%d個結點不存在", i - 1);
        return NULL;
    }

    s = p->Next;                    // s指向第i個結點
    p->Next = s->Next;              // 從鏈表中刪除
    free(s);                        // 釋放被刪除的結點
    return PtrL;
}

平均查找次數爲n/2 ,平均時間性能爲O(n)

廣義表(Generalized List)

  • 廣義表是線性表的推廣
  • 對於線性表而言,n個元素都是基本的單元素
  • 廣義表中,這些元素不僅可以是單元素也可以是另一個廣義表

代碼定義

typedef struct GNode *GList;
struct GNode {
    int Tag;                // 標誌域:0表示結點是單元素,1表示結點是廣義表
    union {                 // 子表指針域Sublist與單元素數據域Data複用,即共用存儲空間
        ElementType Data;
        GList SubList;
    } URegion;
    GList Next;             // 指向後繼結點
};

多重鏈表

鏈表中的結點可能同時隸屬於多個鏈。

  • 多重鏈表中結點的指針域會有多個,如前面例子包含了Next和SubList兩個指針域
  • 但包含兩個指針域的鏈表並不一定是多重鏈表,比如雙向鏈表不是多重鏈表

多重鏈表有廣泛的的用途:基本上如樹、圖這樣相對複雜的數據結構都可以採用多重鏈表方式實現存儲。

多重鏈表存儲矩陣

image

採用一種典型的多重鏈表——十字鏈表來存儲稀疏矩陣:
* 只存儲矩陣非0元素項,結點的數據域:行座標Row、列座標Col、數值Value
* 每個結點通過兩個指針域,把同行、同列串起來:
* 行指針(或稱爲向右指針)Right
* 列指針(或稱爲向下指針)Down

image

  • 用一個標識域Tag來區分頭結點與非0元素結點
  • 頭結點的標識域爲”Head”,矩陣非0元素結點的標識值爲”Term”
    image
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章