第2章 順序表及其順序儲存
目錄
一、線性表
- 線性表:屬於線性結構。有且僅有一個開始結點,有且僅有一個終端結點,其他結點為內部結點。
- 線性表的儲存:順序儲存 or 鏈式儲存
二、順序表
2.1 順序表的基本概念及描述
- 順序表:線性表採用順序儲存的方式
- 注:每個結點佔用\(len\)個記憶體單元,\(location(k_i)\)為順序表中第\(i\)個結點\(k_i\)所佔記憶體空間的第\(1\)個單元的地址
- \(location(k_i) = location(k_i) + len\)
- \(location(k_i) = location(k_1) + (i-1)len\)
2.2 順序表的實現
- 注:陣列中下標為\(i\)的元素對應的是順序表中第\(i+1\)個結點
- 順序表的常用操作(簡單且大概率不考,因此無程式碼展示,後不提醒)
- 順序表的初始化
- 順序表後部進行插入操作
- 列印順序表的各結點值
- 判斷順序表是否為空
- 查詢順序表中值為x的結點位置
- 取得順序表中第i個結點的值
2.2.1 順序表的儲存結構
#define MAXSIZE 100
typedef int datatype;
typedef struct{
datatype a[MAZXSIZE];
int size;
}sequence_list;
2.2.2 順序表的插入操作(程式)
- 將值為\(x\)的結點插入到第\(i\)個位置的步驟:
- 判斷順序表是否是滿的
- 判斷指定的位置是否不存在
- 將\(k_i,\cdots,k_{n-1}\)這些結點對應的陣列元素依次後移一個位置,空出\(k_i\)原先的位置存放新插入的結點。(從後往前移)
- 將值為\(x\)的結點插入到第\(i\)個位置
- 順序表的長度加\(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 順序表的刪除操作(程式)
- 刪除順序表中第\(i\)個結點的步驟:
- 判斷順序表是否為空
- 判斷刪除位置是否存在
- 將順序表中的\(k_{i+1},\cdots,k_{n-1}\)元素依次前移一個位置。(從前往後移)
- 順序表的長度減\(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 棧的基本概念及描述
- 棧:特殊的線性表。插入運算和刪除運算均線上性表的同一端進行
- 棧頂:進行插入(進棧)和刪除(出棧)的一端
- 棧底:不進行操作的一端
- 棧的性質:後進先出(先進後出)
3.2 順序棧及其實現
- 棧(順序儲存)的常用操作:
- 棧的儲存結構
- 棧初始化
- 判斷棧是否為空
- 取得棧頂結點值
- 棧的插入操作
- 棧的刪除操作
3.3 棧的應用之一(括號匹配)
- 括號匹配解決步驟:
- 從左向右掃描表示式
- 遇到開括號則將遇到的開括號存放於棧中
- 遇到閉括號則檢視是否與棧頂結點匹配。匹配刪除棧頂結點,不匹配說明表示式中的括號是不匹配的(結束)
- 掃描整個表示式後,棧是空的,說明表示式中的括號是匹配的;否則是不匹配的(結束)
3.4 棧的應用之二(算術表示式求值)
- 中綴表示式:操作符處於兩個運算元之間
- 字首表示式:操作符處於兩個運算元之前
- 字尾表示式:操作符處於兩個運算元之後
- 字尾表示式求值:每遇到一個操作符,則將前面的兩個運算元執行相應的操作
- 字尾表示式求解步驟:
- 把遇到的運算元暫存於一個棧中
- 遇到操作符,則從棧中取出兩個運算元執行相應的操作,並將結果壓入棧中
- 直到對字尾表示式中最後一個操作符處理完
- 最後壓入棧中的樹就是字尾表示式的計算結果
3.4.1 中綴表示式轉換為字尾表示式步驟
-
從左到右掃描中綴表示式,如果是數字字元和圓點“.”,直接寫入字尾表示式
-
遇到開括號,將開括號壓入棧中,遇到匹配的閉括號,將棧中元素彈出並放入字尾表示式,直到棧頂元素為匹配的開括號時,彈出該開括號
-
遇到的是操作符:
- 遇到的操作符優先順序<=棧頂元素,彈出棧頂元素放入字尾表示式(迴圈判斷)
- 遇到的操作符優先順序>棧頂元素,將遇到的操作符壓入棧中
-
重複上述步驟,直到遇到結束標記“#”,彈出棧中的所有元素並放入字尾表示式陣列中
-
操作符優先順序:\(\#,(,+-,*/\)
-1 | 0 | 1 | 2 |
---|---|---|---|
# | ( | +- | */ |
四、佇列
4.1 佇列的基本概念及描述
- 佇列:一種特殊的線性表。插入(進隊)和刪除(出隊)操作分別在表的兩端進行
- 隊尾:插入的一端
- 對首:刪除的一端
- 佇列的性質:先進先出
4.2 順序佇列及其實現
- 佇列(順序儲存)的常用操作:
- 佇列的順序結構
- 佇列初始化
- 判斷佇列是否為空
- 列印佇列的結點值
- 取得佇列的隊首結點值
- 佇列的插入操作
- 佇列的刪除操作
4.3 順序迴圈佇列及其實現
- 普通佇列的列滿狀態指標:\(rear = MAXSIZE\)
- 迴圈佇列的作用:在普通佇列處於列滿狀態時,利用陣列前部的空閒位置
- 迴圈佇列的列滿狀態指標:
- 設定一個標誌:由於\(rear\)增\(1\)使\(rear = front\),為隊滿;由於\(front\)增\(1\)使\(rear = front\),隊空
- 犧牲一個陣列元素空間:\((rear + 1) \% MAXSIZE = front\),隊滿;\(rear = front\),隊空
- 迴圈佇列(順序儲存)的常用操作(相比較普通佇列在指標增\(1\)中增加一個取模操作):
- 迴圈佇列的插入操作
- 迴圈佇列的刪除操作
五、程式設計習題
5.1 順序表值為x的結點的個數(程式)
設計一個演算法,求順序表中值為x的結點的個數
程式步驟:
- 設定初始值\(c\)計數
- 每找到一個值為\(x\)的結點,計數加\(1\)
- 返回\(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\)的最後一個元素等於原來的第一個元素
程式步驟:
- 定位最後一個元素
- 用\(t\)保留第個一元素的值,並且第一個元素和最後一個元素的值交換
- 迴圈到最後一個元素
// 順序表的儲存結構定義如下(檔名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\)的結點,使順序表中的結點仍然是從小到大有序
程式步驟:
- 從最後一個元素開始與\(x\)比較大小,元素值大於該\(x\)值,則往後挪一個位置
- 找到比\(x\)小的元素停止
- 在該元素的位置上插入\(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++;
}
}