優秀課件筆記之串
來源:互聯網
上載者:User
第四章 串
4.1 串類型的定義
4.2 串的表示和實現
4.2.1 定長順序儲存表示
4.2.2 堆分配儲存表示
4.2.3 串的塊鏈儲存表示
4.3 串的模式比對演算法
一、串及其基本概念
串的定義:串(String)是零個或多個字元組成的有限序列。
一般記作S=“
a1a2a3…
an”
,其中S是串名,雙引號括起來的字元
序列是串值;ai(1≦i≦n)可以是字母、數字或其它字元。
串的長度:串中所包含的字元個數稱為該串的長度。
空串:長度為零的串稱為空白串(Empty String) ,它不包含任何
字元。
空格串:將僅由一個或多個空格組成的串稱為空白格串(Blank
String)。注意:空串和空格串的不同,例如“
”
和“”
分別表
示長度為1的空格串和長度為0的空串。
4.1 串類型的定義
子串與主串:串中任意個連續字元組成的子序列稱為該串的子
串,包含子串的串相應地稱為主串。通常將子串在主串中首
次出現時的該子串的首字元對應的主串中的序號,定義為子
串在主串中的位置。
例如,設A=“
This is a string ”
B=“
is”
則B是A的子串,A
為主串。B在A中出現了兩次,其中首次出現所對應的主串位
置是3。因此,稱B在A中的位置為3。
相等:若且唯若兩個串的長度相等,並且每個對應位置的字元
都相等時,稱兩個串相等。
例如,A=“
BEIJING”
B=“
BEIJING”
,則串A與串B相等。
串常量和串變數:串常量和整常數、實常數一樣,在程式中只
能被引用但不能改變其值,即只能讀不能寫。串變數的值在
程式中可以改變,即可以讀也可以寫。
4.1 串類型的定義
二、串的抽象資料定義
串的抽象資料類型定義見教材P71
三、串的基本操作
對於串的基本操作,許多進階語言均提供了相應的運算或
標準庫函數來實現。下面僅介紹幾種在C語言中常用的串運算。
定義下列幾個變數:
char s1[20]= “
dirtreeformat ”
,
s2[20]=“
file.txt ”
;
char s3[30], *p;
int result;
4.1 串類型的定義
1 求串長(length)
int strlen(char *s); //求串的長度
例如:printf(“
%d”
,strlen(s1)); 輸出13
2 串複製(copy)
char *strcpy(char *to,char *from);
該函數將串from複製到串to中,並且返回一個指向串to的開
始處的指標。
例如:strcpy(s3,s1); //s3= “
dirtreeformat ”
3 聯結(concatenation)
char strcat(char *to,char *from)
該函數將串from複製到串to的末尾,並且返回一個指向串to
的開始處的指標。
例如:strcat(s3 , “
/”
)
strcat(s3,s2); //s3= “
dirtreeformat/file.txt ”
4.1 串類型的定義
4 串比較(compare)
int strcmp(char *s1,char *s2);
該函數比較串s1和串s2的大小,當傳回值小於0,等於0或大
於0時分別表示s1<s2,s1=s2或s1>s2
例如:result=strcmp(“
baker”
,“
Baker”
); //result>0
result=strcmp( “
12”
,“
12”
); //result=0
result= strcmp(“
Jos”
,“
Joseph”
); //result<0
5 字元定位(index)
char strchr(char *s,char c);
該函數是找c在字串中第一次出現的位置,若找到則返回該
位置,否則返回NULL。
例如:p=strchr(s2, “
.”
); //p指向“
file”
之後的位置
if(p) strcpy(p, “
.cpp”
); //s2= “
file.cpp ”
4.1 串類型的定義
2
Page 2
例1、求子串
求子串的過程即為複製字元序列的過程,將串S中的第pos個
字元開始長度為len的字元複製到串T中。
void substr(char *sub,char *s,int pos,int len)
{ if( pos<0 || pos>strlen(s)-1 || len<0 )
error( “
parameter error ”
);
strncpy(sub,s+pos,len );
}
例2、串的定位index(char *s,char *t,int pos)
求串T在主串S中第pos個字元之後的位置。方法:從主串S的第
pos個字元開始,取長度和串T相等的子串和T比較,若相等,則求
得函數值為pos。否則子串位置增1繼續與T比較,直至找到與T相
等的子串或確定S中不存在和串T相等的子串為止。
4.1 串類型的定義
int index(char *s, char *t, int pos)
{ if( pos>0 )
{ n = strlen( s );
m = strlen( t );
i = pos;
while( i<n-m+1 )
{ substr( sub, s, i, m );
if( strcmp( sub, t ) != 0 )
++i;
else return( i );
}
}
return( 0 );
}
4.1 串類型的定義
定長順序儲存表示,也稱為靜態儲存分配的順應表。它是用一組
連續的儲存單元來存放串中的字元序列。所謂定長順序儲存結構,
是直接使用定長的字元數組來定義,數組的上界預先給出:
#define maxstrlen 255
typedef char SString[maxstrlen ]; // 0分量存放串長
4.2 串的表現和實現
4.2.1 定長順序儲存表示
Status SubString( SString &Sub, SString S, int pos, int len )
{ if( pos < 1 || pos > S[0] || len < 0 || len > S[0]-pos+1 )
return ERROR;
Sub[1..len] = S[pos..pos+len-1];
Sub[0] = len;
retrun OK;
}
Status Concat(SString &T, SString S1, Sstring S2)
{ if( S1[0] + S2[0] <= maxstrlen )
{ T[1..S1[0]] = S1[1..S1[0]];
T[S1[0]+1..S1[0]+S2[0]] = S2[1..S2[0]];
T[0] = S1[0] + S2[0]; return TRUE;
}
else if ( S1[0] < maxstrlen )
{ T[1..S1[0]] = S1[1..S1[0]];
T[S1[0]+1..maxstrlen] = S2[1..maxstrlen-S1[0]];
T[0] = maxstrlen; return FALSE;
}
else
{ T[0..maxstrlen] = S1[0..maxstrlen];
return FALSE;
}
}
4.2 串的表現和實現
以一組地址連續的儲存單元存放串值字元序列,但它們的存
儲空間是在程式執行過程中動態分配而得,所以也稱為動態儲存裝置
分配的順序表。在C語言中,利用和等動態儲存裝置管理函數,來根據
實際需要動態分配和釋放字元數組空間。
typedef struct{
char *ch;
int length;
} HString;
4.2.2 堆分配儲存表示
4.2 串的表現和實現
Status strassign(HString t, char *chars){
//產生一個其值等於串常量chars的串t
if(t.ch) free(t.ch);
for(i=0, c=chars; c; ++i, ++c) ; // 求chars的長度
if(!i) { t.ch=NULL; t.length=0; }
else
{ if(!(t.ch=(char *)malloc(i*sizeof(char))))
exit(overflow);
t.ch[0..i-1] = chars[0..i-1];
t.length=i;
}
}
4.2 串的表現和實現
3
Page 3
int strlen(HString s){ return s.length; }
Status clearstring(HString s)
{ if(s.ch) { free(s.ch); s.ch=NULL;}
s.length=0;
}
int strcmp(HString s, HString t)
{ for(i=0; i<s.length && i<t.length; ++i)
if(s.ch[i] != t.ch[i])
return(s.ch[i] - t.ch[i]);
return s.length-t.length;
}
4.2 串的表現和實現
Status concat(HString t, HString s1, HString s2)
{ if(t.ch) free(t.ch);
if(!(t.ch=(char*)malloc((s1.length+s2.length)*sizeof(char))))
exit(overflow);
t.ch[0..s1.length-1]=s1.ch[0..s1.length-1];
t.length=s1.length+s2.length;
t.ch[s1.length..t.length-1]=s2.ch[0..s2.length-1];
return OK;
}
4.2 串的表現和實現
Status substr(HString sub, HString s, int pos, int len)
{ if( pos<1 || pos>s.length || len<0 || len>s.length-pos+1 )
return ERROR;
if(sub.ch) free(sub.ch);
if(!len) { sub.ch=NULL; sub.length=0; }
else
{ sub.ch=(char *)malloc(len*sizeof(char));
sub.ch[0..len-1]=s[pos-1..pos+len-2];
s.length= len;
}
return OK;
}
4.2 串的表現和實現
順序串上的插入和刪除操作不方便,需要移動大量的字
符。因此,可用單鏈表方式來儲存串值,串的這種鏈式儲存
結構簡稱為鏈串。
一個鏈串由頭指標唯一確定。這種結構便於進行插入和
刪除運算,但儲存空間利用率太低。
A B C D E F G H I # # # ^
head
head
A B C I ^
4.2.3 串的塊鏈儲存表示
4.2 串的表現和實現
4.3 串的模式比對演算法
……
S
i-j+1
S
i-j+2
……
S
i-1
S
i
S
i+1
……
P
1
P
2
……
P
j-1
P
j
……
…
失配位置
P
1
P
2
……
P
j-1
P
j
……
下次匹配位置
e.g: S=a b c a b c a b c d
P= a b c a b c d
a b c a b c d
模式右移一位
4.3.1 求子串位置的定位函數Index( )
模式比對:求子串(模式)在主串的位置。
基本方法:從指定位置開始逐個比較主串與模式的字元,一旦
發現出現字元不匹配,則整個模式相對於原來的位
置右移一位。如所示:
最基本的模式比對程式:
int Index( SString S, SString T, int pos )
// 在主串S的第POS個字元之後,尋找模式T的匹配位置
{ i = pos ; j = 1;
while ( i <= S[0] && j <= T[0] ) // 0 號單元存放串長
{ if ( S[i] == T[j] ) { ++i ; ++j ; }
else { i = i - j + 2; j = 1; }
}
if ( j > T[0] ) return i-T[0] // T 在S中的匹配起始位置
else return 0;
}
4.3 串的模式比對演算法
示範
4
Page 4
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
S=
aaaaaaaaab
P=
aab
S=
aaaaaaaaab
P=
aab
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
a
、b
不等
模式右移一位
a
、b
不等
模式右移一位
完全符合
n-m+1
匹配起始位置
4.3 串的模式比對演算法
4.3.2 Knuth-Morris-Pratt
模式比對演算法(KMP
演算法)
說明基本模式比對演算法在最壞情況下時間複雜度為
O
(
n
*
m
)的實
例(n
為主串長度,m
為模式長度)。每比較m
次,移動模式一次。最後
在主串的
n-m+1
找到主串,比較
(n-m+1
)*
m
次
。
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
失配點
右移一位,仍失配又右移一位,仍失配
再右移一位,三次
比較之後,再進行
斷點處的比較,比
較成功!
問題:
能否省去上述五次比
較,直接進行
S7
和
P4
之
間的比較呢?
本次比較省去? 本次比較省去?
三次比較省去?
4.3 串的模式比對演算法
說明
KMP
演算法的執行個體:
i
j
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
失配點
直接尋找新匹配位置
i
j
…
S
i-j+1
S
i-j+2
……
S
i-1
S
i
S
i+1
……
P
1
P
2
……
P
j-1
P
j
……
…
失配點
•
分析:當
S
i
和
P
j
發生失配時,
S
i-j+1
S
i-j+2
……
S
i-1
=
P
1
P
2
……
P
j-1
…
S
i-k
S
i-k+1
……
S
i-1
S
i
S
i+1
……
P
1
……
P
k-1
P
k
……
…
失配點
如果:
P
1
P
2
………
P
k-1
= P
j-k+1
P
j-k+2
………
P
j-1
;
可以直接比較S
i
和
P
k
4.3 串的模式比對演算法
int
Index_KMP( SString S, SString T, int
pos )
// 在主串S的第POS個字元之後,尋找模式T的匹配位置
// 已知 NEXT 函數值,T 非空,1<=pos<=Strlength(S)
{ i = pos ; j = 1;
while
( i <= S[0] &&
j <= T[0] )
{ if
( j == 0 || S[i] == T[j] ) { ++i ; ++j ; }
else
j = next[ j ];
}
if
( j > T[0] ) return
i-T[0] // T在S中的匹配起始位置
else return
0;
} // Index_KMP