第2章 順序表及其順序存儲


第2章 順序表及其順序存儲

數據結構與算法_師大完整教程目錄(更有python、go、pytorch、tensorflow、爬蟲、人工智能教學等着你):https://www.cnblogs.com/nickchen121/p/13768298.html

一、線性表

  1. 線性表:屬於線性結構。有且僅有一個開始結點,有且僅有一個終端結點,其他結點為內部結點。
  2. 線性表的存儲:順序存儲 or 鏈式存儲

二、順序表

2.1 順序表的基本概念及描述

  1. 順序表:線性表采用順序存儲的方式

  2. 注:每個結點占用\(len\)個內存單元,\(location(k_i)\)為順序表中第\(i\)個結點\(k_i\)所占內存空間的第\(1\)個單元的地址

    1. \(location(k_i) = location(k_i) + len\)
    2. \(location(k_i) = location(k_1) + (i-1)len\)

2.2 順序表的實現

  1. 注:數組中下標為\(i\)的元素對應的是順序表中第\(i+1\)個結點

  2. 順序表的常用操作(簡單且大概率不考,因此無代碼展示,后不提醒)

    1. 順序表的初始化
    2. 順序表后部進行插入操作
    3. 打印順序表的各結點值
    4. 判斷順序表是否為空
    5. 查找順序表中值為x的結點位置
    6. 取得順序表中第i個結點的值

2.2.1 順序表的存儲結構

#define MAXSIZE 100
typedef int datatype;
typedef struct {
    datatype a[MAZXSIZE];
    int size;
} sequence_list;

2.2.2 順序表的插入操作(算法)

  1. 將值為\(x\)的結點插入到第\(i\)個位置的步驟:

    1. 判斷順序表是否是滿的
    2. 判斷指定的位置是否不存在
    3. \(k_i,\cdots,k_{n-1}\)這些結點對應的數組元素依次后移一個位置,空出\(k_i\)原先的位置存放新插入的結點。(從后往前移)
    4. 將值為\(x\)的結點插入到第\(i\)個位置
    5. 順序表的長度加\(1\)
#define MAXSIZE 100
typedef int datatype;
typedef struct {
    datatype a[MAZXSIZE];
    int size;
} sequence_list;

void insert(sequence_list *slt, datatype x, int position) {
    int i;
    if (slt->size == MAXSIZE) {
        printf("\n順序表是滿的!沒法插入!");
        exit(1);
    }
    if (position < 0 || position > slt->size) // 如size為10,slt->a[i-1=9]存在,既可以不用>=
    {
        printf("\n指定的插入位置不存在!");
        exit(1);
    }
    for (i = slt->size; i > position; i--) {
        slt->a[i] = slt->a[i - 1];
    }
    slt->a[position] = x;
    slt->size++;
}

時間復雜度:\(O(n)\)

2.2.3 順序表的刪除操作(算法)

  1. 刪除順序表中第\(i\)個結點的步驟:

    1. 判斷順序表是否為空
    2. 判斷刪除位置是否存在
    3. 將順序表中的\(k_{i+1},\cdots,k_{n-1}\)元素依次前移一個位置。(從前往后移)
    4. 順序表的長度減\(1\)
#define MAXSIZE 100
typedef int datatype;
typedef struct {
    datatype a[MAZXSIZE];
    int size;
} sequence_list;

void dele(sequence_list *slt, int position) {
    int i;
    if (slt->size == 0) {
        pringf("\n順序表是空的!");
        exit(1);
    }
    if (position < 0 || position >= slt->size) // 如size為10,postion為10,slt->a[i+1=11]不存在,即不可以>
    {
        printf("\n指定的刪除位置不存在!");
        exit(1);
    }
    for (i = position; i < slt->size - 1; i++) // 循環到倒數第二個元素即可,因為后面是a[i+1]
    {
        slt->a[i] = slt->a[i + 1];
    }
    slt->size--;
}

時間復雜度:\(O(n)\)

三、棧

3.1 棧的基本概念及描述

  1. 棧:特殊的線性表。插入運算和刪除運算均在線性表的同一端進行
  2. 棧頂:進行插入(進棧)和刪除(出棧)的一端
  3. 棧底:不進行操作的一端
  4. 棧的性質:后進先出(先進后出)
  5. 出棧元素不同排列個數:\(\frac{1}{n+1}C_{2n}^{n}\)

3.2 順序棧及其實現

  1. 棧(順序存儲)的常用操作:

    1. 棧的存儲結構
    2. 棧初始化
    3. 判斷棧是否為空
    4. 取得棧頂結點值
    5. 棧的插入操作
    6. 棧的刪除操作

3.2.1 順序棧的存儲結構

#define MAXSIZE 100
typedef int datatype;
typedef struct {
    datatype a[MAXSIZE];
    int top;
} sequence_stack;

3.3 棧的應用之一(括號匹配)

  1. 括號匹配解決步驟:

    1. 從左向右掃描表達式
    2. 遇到開括號則將遇到的開括號存放於棧中
    3. 遇到閉括號則查看是否與棧頂結點匹配。匹配刪除棧頂結點,不匹配說明表達式中的括號是不匹配的(結束
    4. 掃描整個表達式后,棧是空的,說明表達式中的括號是匹配的;否則是不匹配的(結束

3.4 棧的應用之二(算術表達式求值)

  1. 中綴表達式:操作符處於兩個操作數之間

  2. 前綴表達式:操作符處於兩個操作數之前

  3. 后綴表達式:操作符處於兩個操作數之后

  4. 后綴表達式求值:每遇到一個操作符,則將前面的兩個操作數執行相應的操作

  5. 后綴表達式求解步驟:

    1. 把遇到的操作數暫存於一個棧中
    2. 遇到操作符,則從棧中取出兩個操作數執行相應的操作,並將結果壓入棧中
    3. 直到對后綴表達式中最后一個操作符處理完
    4. 最后壓入棧中的樹就是后綴表達式的計算結果

3.4.1 中綴表達式轉換為后綴表達式步驟

  1. 從左到右掃描中綴表達式,如果是數字字符和圓點“.”,直接寫入后綴表達式

  2. 遇到開括號,將開括號壓入棧中,遇到匹配的閉括號,將棧中元素彈出並放入后綴表達式,直到棧頂元素為匹配的開括號時,彈出該開括號

  3. 遇到的是操作符:

    1. 遇到的操作符優先級<=棧頂元素,彈出棧頂元素放入后綴表達式(循環判斷)
    2. 遇到的操作符優先級>棧頂元素,將遇到的操作符壓入棧中
  4. 重復上述步驟,直到遇到結束標記“#”,彈出棧中的所有元素並放入后綴表達式數組中

  5. 操作符優先級:\(\#,(,+-,*/\)

-1 0 1 2
# ( +- */

四、隊列

4.1 隊列的基本概念及描述

  1. 隊列:一種特殊的線性表。插入(進隊)和刪除(出隊)操作分別在表的兩端進行
  2. 隊尾:插入的一端
  3. 對首:刪除的一端
  4. 隊列的性質:先進先出

4.2 順序隊列及其實現

  1. 隊列(順序存儲)的常用操作:
  2. 隊列初始化
  3. 判斷隊列是否為空
  4. 打印隊列的結點值
  5. 取得隊列的隊首結點值
  6. 隊列的插入操作
  7. 隊列的刪除操作

4.2.1 順序隊列的存儲結構

#define MAXSIZE 100
typedef int datatype;
typedef struct {
    datatype a[MAXSIZE];
    int front;
    int rear;
} sequence_queue;

4.3 順序循環隊列及其實現

  1. 普通隊列的列滿狀態指標:\(rear = MAXSIZE\)

  2. 循環隊列的作用:在普通隊列處於列滿狀態時,利用數組前部的空閑位置

  3. 循環隊列的列滿狀態指標:

    1. 設置一個標志:由於\(rear\)\(1\)使\(rear = front\),為隊滿;由於\(front\)\(1\)使\(rear = front\),隊空
    2. 犧牲一個數組元素空間:\((rear + 1) \% MAXSIZE = front\),隊滿;\(rear = front\),隊空
  4. 循環隊列(順序存儲)的常用操作(相比較普通隊列在指針增\(1\)中增加一個取模操作):

    1. 循環隊列的插入操作
    2. 循環隊列的刪除操作

4.3.1 順序循環隊列的存儲結構

#define MAXSIZE 100
typedef int datatype;
typedef struct {
    datatype a[MAXSIZE];
    int front;
    int rear;
} sequence_queue;

五、算法設計題

5.1 順序表值為x的結點的個數(算法)

設計一個算法,求順序表中值為x的結點的個數

算法步驟:

  1. 設定初始值\(c\)計數
  2. 每找到一個值為\(x\)的結點,計數加\(1\)
  3. 返回\(c\)
// 順序表的存儲結構定義如下(文件名seqlist.h)
#include <stdio.h>

#define N 100 // 預定義最大的數據域空間
typedef int datatype; // 假設數據類型為整型
typedef struct {
    datatype data[N]; // 此處假設數據元素只包含一個整型的關鍵字域
    int length; // 線性表長度
} seqlist; // 預定義的順序表類型

// 算法countx(L, x)用於求順序表L中值為x的結點的個數
int countx(seqlist *L, datatype x) {
    int c = 0;
    int i;
    for (i = 0; i < L->length; i++) {
        if (L->data[i] == x) c++;
    }
    return c;
}

5.2 順序表倒置(算法)

設計一個算法,將一個順序表倒置。即,如果順序表各個結點值存儲在一維數組\(a\)中,倒置的結果是使得數組\(a\)中的\(a[o]\)等於原來的最后一個元素,\(a[1]\)等於原來的倒數第\(2\)個元素,\(\cdots\)\(a\)的最后一個元素等於原來的第一個元素

算法步驟:

  1. 定位最后一個元素
  2. \(t\)保留第個一元素的值,並且第一個元素和最后一個元素的值交換
  3. 循環到最后一個元素
// 順序表的存儲結構定義如下(文件名seqlist.h)
#include <stdio.h>

#define N 100 // 預定義最大的數據域空間
typedef int datatype; // 假設數據類型為整型
typedef struct {
    datatype data[N]; // 此處假設數據元素只包含一個整型的關鍵字域
    int length; // 線性表長度
} seqlist; // 預定義的順序表類型

// 算法verge(L)用於順序表倒置
void verge(seqlist *L) {
    int t, i, j;
    i = 0;
    j = L->length - 1;
    while (i < j) {
        t = L->data[i];
        L->data[i++] = L->data[j];
        L->data[j--] = t;
    }
}

5.3 有序順序表插入結點並仍然有序(真題)(算法)

已知一個順序表中的各結點值是從小到大有序的,設計一個算法,插入一個值為\(x\)的結點,使順序表中的結點仍然是從小到大有序

算法步驟:

  1. 從最后一個元素開始與\(x\)比較大小,元素值大於該\(x\)值,則往后挪一個位置
  2. 找到比\(x\)小的元素停止
  3. 在該元素的位置上插入\(x\)
// 順序表的存儲結構定義如下(文件名seqlist.h)
#include <stdio.h>

#define N 100 // 預定義最大的數據域空間
typedef int datatype; // 假設數據類型為整型
typedef struct {
    datatype data[N]; // 此處假設數據元素只包含一個整型的關鍵字域
    int length; // 線性表長度
} seqlist; // 預定義的順序表類型

// 算法insertx(L, x)用於有序順序表插入結點並仍然有序
void insertx(seqlist *L, datatype x) {
    int j;
    if (L->length < N) {
        j = L->length - 1;
        while (j >= 0 && L->data[j] > x) {
            L->data[j + 1] = L->data[j]; // 元素統一往后挪
            j--;
        }
        L->data[j + 1] = x;
        L->length++;
    }
}

六、錯題集

  1. 長為 \(n\) 的順序表中,任意位置插入的可能次數為n+1​次(包括頭前和尾后)

  2. 設棧 \(S\) 和隊列 \(Q\) 的初始狀態為空,元素 e1、$e\(2、\)e\(3、\)e\(4、\)e$5 和 $e$6 依次通過棧 \(S\)
    一個元素出棧后即進入隊列 \(Q\),若 6 個元素出隊的序列為 $e\(2、\)e\(4、\)e\(3、\)e\(6、\)e$5 和 $e$1,則棧 \(S\)
    的容量至少應該為3

  3. 編號為 \(1,2,3,4\) 的四列火車通過一個棧式的列車調度站,可能得到的調度結果總共有14種

    1. 使用公式:出棧元素不同排列個數為 \(\frac{1}{n+1}C_{2n}^{n}\)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM