資料結構C語言 Part4 串、陣列和廣義表
首先,我們目前提到的(Part1-Part4)都是線性結構。
這一節,我們主要是要掌握:
1. 瞭解串的儲存方法,理解串的兩種模式匹配演算法,重點掌握BF演算法。
2. 明確陣列和廣義表這兩種資料結構的特點,掌握陣列地址計算方法,瞭解幾種特殊矩陣的壓縮儲存方法。
3.掌握廣義表的定義、性質及其GetHead和GetTail的操作。
我們先來看看串(string):
其引數有串名,串值,串長,主串,字串,串相等,空串,字元位置,字串位置。
//順序儲存 typedef struct { char *ch; int length; }MyString; //鏈式,多個字元存在一個結點 #define CHUNKSIZE 80 //可由使用者定義的塊大小 typedef struct Chunk{ char ch[CHUNKSIZE]; struct Chunk *next; }Chunk; typedef struct{ Chunk *head,*tail; //串的頭指標和尾指標 int curlen; //串的當前長度 }LString;
串的模式匹配演算法:確定主串中所含子串第一次出現的位置(定位),方法主要是:
BF演算法(又稱古典的、經典的、樸素的、窮舉的) & KMP演算法(特點:速度快)
對於BF演算法,將主串的第pos個字元和模式的第一個字元比較,
若相等,繼續逐個比較後續字元; 若不等,從主串的下一字元起,重新與模式的第一個字元比較。
直到主串的一個連續子串字元序列與模式相等 。返回值為S中與T匹配的子序列第一個字元的序號,即匹配成功。 否則,匹配失敗,我們設返回值 -1。
可見,它的最壞的時間複雜度是O(n*m)這個Scale的。
//暴力檢索演算法描述 int ViolentMatch(char* s, char* p) { int sLen = strlen(s); int pLen = strlen(p); int i = 0; int j = 0; while (i < sLen && j < pLen) { if (s[i] == p[j]) { //如果當前字元匹配成功(即S[i] == P[j]),則i++,j++ i++; j++; } else { //②如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0 i = i - j + 1; j = 0; } } //匹配成功,返回模式串p在文字串s中的位置,否則返回-1 if (j == pLen) return i - j; else return -1; }
對於KMP(Knuth Morris Pratt所提出的)演算法,另一位CSDN的大神寫的很好:深度理解KMP連結?。核心是利用已經部分匹配的結果二加快模式串的滑動速度,主串的指標i不必回溯,這樣可以提速到O(n+m)。
int KmpSearch(char* s, char* p) { int i = 0; int j = 0; int sLen = strlen(s); int pLen = strlen(p); while (i < sLen && j < pLen) { //①如果j = -1,或者當前字元匹配成功(即S[i] == P[j]),都令i++,j++ if (j == -1 || s[i] == p[j]) { i++; j++; } else { //②如果j != -1,且當前字元匹配失敗(即S[i] != P[j]),則令 i 不變,j = next[j] //next[j]即為j所對應的next值 j = next[j]; } } if (j == pLen) return i - j; else return -1; } //優化過後的next 陣列求法 void GetNext(char* p,int next[]) { int pLen = strlen(p); next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) { //p[k]表示字首,p[j]表示字尾 if (k == -1 || p[j] == p[k]) { ++k; ++j; next[j] = k; } else { k = next[k]; } } }
原理圖:
細節我們不一一贅述了,畢竟時間有限。
然後我們看看資料結構書上的陣列:
我們就看看題算了:
同理,我們引申到三維陣列,也有LOC ( i1, i2, i3 ) = a + i1* m2 * m3 + i2* m3 + i3。a代表起始地址。
要引起注意的是,這裡我們是以0為起點,每一行有m個元素,從0到m-1.有的題可能會比較繞。
然後我們再看看特殊矩陣的壓縮:
1. 什麼是壓縮儲存? 若多個數據元素的值都相同,則只分配一個元素值的儲存空間,且零元素不佔儲存空間。
2. 什麼樣的矩陣能夠壓縮? 一些特殊矩陣,如:對稱矩陣,對角矩陣,三角矩陣,稀疏矩陣等。
3. 什麼叫稀疏矩陣? 矩陣中非零元素的個數較少(一般小於5%)。
舉幾個例子:
最後看看廣義表:
廣義表(列表): n ( >=0 )個表元素組成的有限序列,記作LS = (a0, a1, a2, …, an-1) , LS是表名,ai是表元素,它可以是表 (稱為子表),可以是資料元素(稱為原子)。 n為表的長度。n = 0 的廣義表為空表。
基本運算:
(1)求表頭GetHead(L):非空廣義表的第一個元素,可以是一個單元素,也可以是一個子表
(2)求表尾GetTail(L):非空廣義表除去表頭元素以外其它元素所構成的表。表尾一定是一個表