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

二十一歲的有德發表於2020-09-25

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

一、線性表

  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. 棧的性質:後進先出(先進後出)

3.2 順序棧及其實現

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

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

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. 迴圈佇列的刪除操作

五、程式設計習題

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++;
  }
}

相關文章