1.基本的な考え方
- 文字列の定義:文字列は、0個以上の文字で構成される有限のシーケンスです。文字列内の文字数は文字列の長さと呼ばれ、要素がゼロの文字列は空の文字列と呼ばれます。
- 部分文字列:文字列内の連続する文字で構成される部分列。メイン文字列:部分文字列を含む文字列。部分文字列の最初の文字の位置は、メイン文字列内の部分文字列の位置と見なされます。スペース文字列:1つ以上のスペースで構成される文字列。文字列は、要素を文字として定義する線形リストです。
- 文字列内の特定の部分文字列の配置操作は、文字列のパターンマッチングと呼ばれ、配置される部分文字列はパターン文字列と呼ばれます。
第二に、文字列の構造
- 固定長シーケンシャルストレージは構造定義を意味します
typedef struct
{
char str[msxSize+1];//maxSize为已经定义的常量,表示串的最大长度,+1是指"\0"
int length;
} Str;
可変長割り当てストレージ表現
typedef struct
{
char *ch;//指向动态分配存储区首地址的字符指针
int length; //串的长度
} Str;
このストレージメソッドでは、長さlengthおよびcharタイプの連続ストレージスペースを割り当てるためにmalloc()関数が必要であり、割り当てられたスペースはfree()関数で解放できます。malloc()を使用してストレージスペースを割り当てます。成功した場合は、文字列のベースアドレスとして開始アドレスへのポインタを返します。割り当てが失敗した場合は、NULLを返します。
三、文字列の基本操作
- 割り当て操作-配列内の各要素を1つずつ割り当てますstrasssign()
int strassign(Str& str,char *ch)
{
if(str.ch)
free(str.ch);//释放原来的空间
int len=0;
char *c=ch;
while(c)
{
len++;
c++;
}
if(len==0)
{
str.ch=NULL;
str.length=0;
return true;
}
else
{
str.ch=(char)malloc(sizeof(char)*(len+1));//多一个用于存放\0
if(str.ch==NULL)
return false;
else
{
c=ch;
for(int i=0;i<=len;i++,c++)//\0也被存入str.ch
str.ch[i]=*c;
str.length=len;
return true;
}
}
}
- 文字列長演算
int strlength(Str str)
{
return str.length;
}
- 文字列比較操作-文字列ソートのコア操作
int strcompare(Str s1,Str s2)
{
for(int i=0;i<s1.length&&i<s2.length;i++)
if(s1.ch[i]!=s2.ch[i])
return s1.ch[i]-s2.ch[i];
return s1.length-s2.length;
}
- 文字列連結操作-2つの文字列を端から端まで連結し、それらを新しい文字列にマージします
int concat(Str& str,Str s1,Str s2)
{
if(str.ch)
{
free(str.ch);
str.ch=NULL;
}
str.ch=(char*)malloc(s1.length+s2.length+1);
if(str.ch==NULL)
return false;
int i=0;
for(;i<s1.length;i++)
str.ch[i]=s1.ch[i];
int j=0;
for(;j<=s2.length;j++)//注意此处为<=,因为要放入\0
str.ch[i+j]=s2.ch[j];
str.length=s1.length+s2.length;
return true;
}
- 部分文字列操作
int substring(Str& substr,Str str,int pos,int len)
{
if(pos<0||pos>str.length||len<0||len>str.length)
return false;
if(substr.ch!=NULL)
{
free(substr.ch);
substr.ch=NULL;
}
if(len==0)
{
substr.ch==NULL;
substr.length=0;
return true;
}
else
{
substr.ch=(char*)malloc(sizeof(char)*(len+1));
int i=pos;
int j=0;
while(i<pos+len)
{
substr.ch[j]=str.ch[i];
++i;
++j;
}
substr.ch[pos+len]=NULLL;
substr.length=len;
return true;
}
}
- 文字列クリア操作
int clearstring(Str& str)
{
if(str.ch)
{
free(str.ch);
str.ch=NULL;
}
str.length=0;
return true;
}
4つの文字列パターンマッチングアルゴリズム
- 単純なパターンマッチングアルゴリズム
int index(Str str,Str substr)
{
int i,j,k;
i=0,j=0,k=i;
while(i<str.length&&j<substr.length)
{
if(str.ch[i]==substr.ch[j])
{
++i;
++j;
}
else
{
j=0;
i=++k;
}
}
if(j==substr.length)
return true;
else
return -1;
}
- KMPアルゴリズム
- 上記の単純なパターンマッチングアルゴリズムにより、ABABABABABタイプが繰り返されているときにバックトラックするたびに、元の方法でのバックトラックは非常に愚かに見えることがわかります。これに基づいて、KMPアルゴリズムが最適化されます。部分一致の有効な情報を使用して、iポインタがバックトラックしないようにします。jポインタを変更することで、パターン文字列を可能な限り有効な位置に移動できます。ABABABABタイプの場合、AB部分をスキップして直接一致させることができます。異なる位置x。このメソッドを実装するには、NEXT配列を定義する必要があります。メイン文字列がパターン文字列と一致しない場合、パターン文字列をNEXT配列の対応する位置に直接ジャンプして、メイン文字列を作成できます。バックトラックする必要はありません。
- 全体的な考え方:一致するプレフィックスの中から最長の一致するサフィックスサブストリングと最長の一致するプレフィックスサブストリングを見つけ、次のラウンドで2つを直接整列させて、パターンストリングの高速移動を実現します。
一致する最長のサフィックスとプレフィックスのサブストリングを見つけます。事前にコレクションにキャッシュします。次に配列をキャッシュし、次にコレクションに移動して、使用時にフェッチします。
- パターン文字列を前処理して、次の配列を生成します
- メインループに入り、メイン文字列
2.1をトラバースします。メイン文字列とパターン文字列
2.2の文字を比較します。不正な文字が見つかった場合は、次の配列をクエリして、一致したプレフィックスに対応する最長の一致するプレフィックスサブストリングを取得し、移動しますパターン文字列を対応する位置に
2.3。現在の文字が一致する場合は、ループを続行します。
void GetNext(Str str,int *next)
{
next[0]=-1;
int j=0;
int k=-1;
while(j<str.length-1)
{
if(k==-1||str.ch[k]==str.ch[j])
{
k++;
j++;
next[j]=k;
}
else
k=next[k];
}
}
- KMPアルゴリズム
int KMP(Str str,Str substr,int *next)
{
int j=0;
int i=0;
while(i<=str.length&&j<=substr.length)
{
if(j==0||str.ch[i]==substr.ch[j])
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j>substr.length)
return i-substr.length;
else
return 0;
}