串
1. 串的定義和實現
字符串簡稱串,計算機上非數值處理的對象基本都是字符串數據。我們常見的信息檢索系統、文本編輯程序、問答系統、自然語言翻譯系統等,都是以字符串數據作爲處理對象的。
1.1 串的定義
串是由零個或者多個字符組成的有限序列。一般記爲S = ‘a1a2a3a4…an’(n>=0).其中S是串名,單引號括起來的字符序列是串的值;ai可以是字母、數字或其他字符;串中字符的個數n稱爲串的長度。n=0時的串稱爲空串。
串中任意個連續的字符組成的子序列稱爲該串的子串,包含子串的串相應地稱爲主串。某個字符在串中的序號稱爲該字符在串中的位置。子串在主串中的位置以子串的第一個字符在主串中的位置來表示。當兩個串的長度相等且每個對應位置的字符都相等時,稱這兩個串是相等的。
注意:由一個或多個空格組成的串稱爲空格串,其長度爲串中空格字符的個數
1.2 串的存儲結構
1.2.1 定義順序存儲表示
類似於線性表的順序存儲結構,用一組地址連續的存儲單元存儲串值得字符序列。在串長順序存儲結構中,爲每個串變量分配一個固定長度得存儲區,既定長數組。
#define MAXLEN 25 //預定義最大串長爲255
typedef struct {
char ch[MAXLEN];//每個分量存儲一個字符
int length; //串的實際長度
}SString;
串的實際長度只能小於等於MAXLEN,超過預定義長度的串值會被捨去,稱爲截斷。串長有兩種表示方法:一是如上述定義描述那樣,用一個額外的變量len來存放串的長度;二是在串值後面加一個不計串長的結束標記字符“\0”,此時的串長爲隱含值。
在一些串的操作中,若串值序列的長度超過上界MAXLEN,約定用“截斷”法處理,要克服這種弊端,只能不限定串長的最大長度,採用動態分配的方式。
1.2.2 堆分配存儲表示
堆分配存儲表示仍然以一組地址連續的存儲單元存放串值的字符序列,但它們的存儲空間是在程序執行過程中動態分配得到的。
typedef struct
{
char *ch; //按串長分配存儲區,ch指向串的基地址
int length; //串的長度
}HString;
在c語言中,存在一個稱之爲“堆”的自由存儲區,並用malloc()和free()函數來完成動態管理。利用malloc()爲每個新產生的串分配一塊實際串所需的存儲空間,若分配成功,則返回一個指向起始地址的指針,作爲串的基地址,這個串由ch指針來表示;若分配失敗,則返回NULL,已分配的空間可用free()釋放掉。
1.2.3 塊鏈存儲表示
類似於線性表的鏈式存儲結構,也可採用鏈表方式存儲串值。由於串的特殊性(每個元素只有一個字符),在具體實現時,每個結點既可以存放一個字符,也可以存放多個字符。每個結點稱爲塊,整個鏈表稱爲塊鏈結構。
如下圖結點大小爲2的鏈表
1.3 串的基本操作
StrAssign(&T,chars):賦值操作。把串T賦值爲chars。
StrCopy(&T,S):複製操作。由串S複製得到串T。
StrEmpty(S):判空操作。若S爲空串,則返回TRUE,反則返回FALSE.
StrCompare(S,T):比較操作。若S>T,返回>0;若S=T,則返回值=0;若S<T則返回值<0.
StrLength(S):求串長。返回串S的元素個數。
SubSring(&Sub,S, pos,len):求子串。用Sub返回串S的第pos個字符起長度爲len的子串。
Concat(&T,S1,S2):串聯接。用T返回由S1和S2聯接而成的新串。
Index(S,T):定位操作。若主串S中存在與串T值相同的子串,則返回它在主串S中第一次出現的位置;否則函數值爲0.
ClearString(&S):清空操作。將S清爲空串。
DestroyString(&S):銷燬串。將串S銷燬。
不同的高級語言對串的基本操作集可以有不同的定義方法。在上述定義的操作中,串賦值StrAssign、串比較StriCompare、求串長StrLength、串聯接Concat及求子串SubString五種操作構成串類型的最小操作子集,即這些操作不可能利用其他串操作來實現;反之,其他串操作(除串清除ClearString和串銷燬DestroyString外)均可在該最小操作子集上實現。
2. 串的模式匹配
2.1 簡單的模式匹配算法
子串的定位操作通常稱爲串的模式匹配,它求的是子串(常稱模式串)在主串中的位置。這裏採用定長順序存儲結構,給出一種不依賴於其他串操作的暴力匹配算法。
int Index(SString S, SString T)
{
int i =1,j= i;
while(i<=S.length && j <=T.length){
if(S.ch[i] == T.ch[j])
{
++i;
++j; //繼續比較後繼字符
}
else{
i = i-j+2;
j = 1;//指針後退重新開始匹配
}
}
if(j>T.length)
return i-T.length;
else return 0;
}