串的相关概念及操作
串的定义
串:是由零个或多个字符组成的有限序列。
空串:不包含任何字符的串称为空串。
子串:串中任意个连续的字符组成的子序列称为该串的子串。
空格串:由一个或多个空格组成的串称为空格串(空格串不是空串,其长度为串中空格字符的个数)。
串的存储结构
定长顺序存储表示
类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列。在串的顺序存储结构中,为每个串变量分配一个固定长度的存储区,即定长数组。
#define MAXSIZE 255 //预定于最大串长为255
typedef struct {
char ch[MAXSIZE]; //每个分量存储一个字符
int length; //串的实际长度
} SString;
堆分配存储表示
堆分配存储表示仍然以一组地址连续的存储单元存放串值得字符序列,但它们得存储空间是在执行过程中动态分配得到的。
typedef struct{
char *ch; //按串长分配存储去,ch指向串的基地址
int length; //串的长度
}HString;
块链存储表示
由于串的特殊性(每个元素只有一个字符),在具体实现时,每个结点既可以存放一个字符,也可以存放多个字符。
每个结点称为块,整个链表称为块链结构。
串的相关操作
- 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
- StrEngth(S): 求串长。返回串S的元素个数
- Substring(&Sub,S,pos,1en):求子串。用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、串比较 StrCompare、求串长Strength、串联接 Concat及求子串Substring五种操作构成串类型的最小操作子集,即这些操作不可能利用其他串操作来实现;反之,其他串操作(除串清除Clearstring和串销毁 Destroystring外)均可在该最小操作子集上实现。 例如,可利用判等、求串长和求子串等操作实现定位函数 Index(S,T)。
串的模式匹配
简单的模式匹配算法
子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位置。这里采用静态顺序存储结构,给出一种不依赖于其他串操作的暴力匹配算法.
算法思想
从主串的第一个字符起,与子串的第一个字符比较,若相等,则继续逐个比较后续字符;若不相等,则从主串的下一个字符起,重新和子串的字符比较,以此类推。
缺点:当某些子串与模式串能部分匹配时,主串的扫描指针经常回溯,导致时间开销大
暴力模式匹配算法的最坏时间复杂度为 O(nm) 其中 n 和 m 分别为主串和子串的长度。
完整代码
#include<stdio.h>
#include<string.h>
#define MAXSIZE 255 //预定于最大串长为255
typedef struct{
char ch[MAXSIZE]; //每个分量存储一个字符
int length; //串的实际长度
} SString;
//初始化串
void InitString(SString &S, SString &T) {
for (int i = 0; i < MAXSIZE; ++i) {
S.ch[i] = '\0';
T.ch[i] = '\0';
}
S.length = 0;
T.length = 0;
}
int Index(SString S, SString T){
int i = 0, j = 0;
while(i < S.length && j < T.length){
if(S.ch[i] == T.ch[j]){
++i; ++j; //继续比较后继字符
}else{
//指针后退重新开始匹配
i = i-j+1;
j = 0;
}
}
if(j >= T.length){
return i - T.length;
}else{
return 0;
}
}
int main(){
SString S,T;
InitString(S, T);//初始化串
char a[15] = {'h','o','l','l','o','h','e','l','l','o','h','l','l','e','o'};
strcpy(S.ch, a); // a数组复制给S的数组
S.length = 15;
for(int i = 0;i < S.length;i++){//打印S的数组
printf("%2c", S.ch[i]);
}
printf("\n");
char b[5] = {'h','e','l','l','o'};
strcpy(T.ch, b);// b数组复制给S的数组
T.length = 5;
for(int i = 0;i < T.length;i++){//打印T的数组
printf("%2c", T.ch[i]);
}
printf("\n");
int flag = Index(S, T);
printf("%d\n", flag);
if(flag){
printf("find it and the number is %d\n", flag);
}else{
printf("cannot find!\n");
}
return 0;
}
KMP算法
求解next数组
//计算next数组
void Getnext(SString T, int *next)
{
for(int j = 0; j < 5; j++ ){
next[j] = 0;
}
int i,k;
i=0;
k=-1;
next[0]=-1;
while (i<T.length - 1) /* 此处T[0]表示串T的长度 */
{
if(k==-1 || T.ch[i]== T.ch[k])
{
i++;
k++;
next[i] = k;
}
else
k= next[k]; /* 若字符不相同,则k值回溯 */
}
for(int j = 0; j < 5; j++ ){
printf("%2d", next[j] + 1);
}
}
KMP匹配算法
//KMP算法的匹配过程
int IndexKMP(SString S, SString T, int *next){
int i = 0;
int j = 0;
while(i < S.length && j < T.length){
if(j == -1 || S.ch[i] == T.ch[j]){
++i;
++j;
}
else{
j = next[j];
}
}
if(j > T.length -1)
return i - j + 1;
else
return 0;
}
KMP完整代码
目标串:a b a b c a b c a c b a b
模式串:a b c a c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Maxsize 255
typedef struct{
char ch[Maxsize];//存放字符
int length;//串的实际长度
}SString;
//初始化
void InitString(SString &S,SString &T){
for(int i = 0; i < Maxsize; i++){
S.ch[i] = '\0';
T.ch[i] = '\0';
}
S.length = 0;
T.length = 0;
}
//计算next数组
void Getnext(SString T, int *next)
{
for(int j = 0; j < 5; j++ ){
next[j] = 0;
}
int i,k;
i=0;
k=-1;
next[0]=-1;
while (i<T.length - 1) /* 此处T[0]表示串T的长度 */
{
if(k==-1 || T.ch[i]== T.ch[k])
{
i++;
k++;
next[i] = k;
}
else
k= next[k]; /* 若字符不相同,则k值回溯 */
}
for(int j = 0; j < 5; j++ ){
printf("%2d", next[j]);
}
}
//打印字符数组
void PrintString(SString S, SString T){
for(int i = 0;i < S.length;i++){
printf("%2c", S.ch[i]);
}
printf("\n");
for(int i = 0;i < T.length;i++){
printf("%2c", T.ch[i]);
}
printf("\n");
}
//KMP算法的匹配过程
int IndexKMP(SString S, SString T, int *next){
int i = 0;
int j = 0;
while(i < S.length && j < T.length){
if(j == -1 || S.ch[i] == T.ch[j]){
++i;
++j;
}
else{
j = next[j];
}
}
if(j > T.length -1)
return i - j + 1;
else
return 0;
}
int main(){
SString S, T;
InitString(S, T); //初始化
char a[13] = {'a','b','a','b','c','a','b','c','a','c','b','a','b'};
char b[5] = {'a','b','c','a','c'};
strcpy(S.ch, a);//将a数组中的字符复制到S数组中
S.length = 13;
strcpy(T.ch, b);//将b数组中的字符复制到T数组中
T.length = 5;
PrintString(S, T);//打印字符串
int *next = (int*)malloc(6*sizeof(int));
Getnext(T, next);//求解next数组
printf("\n");
int index = IndexKMP(S, T, next);//KMP匹配算法
if(index){
printf("The same string is %d", index);
}
else{
printf("The same string cannot find");
}
return 0;
}