數據結構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):非空廣義表除去表頭元素以外其它元素所構成的表。表尾一定是一個表

 

 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章