Brute Force
int StrBruteForce(LinkString* s, LinkString* t)
{
LinkString* p = s;
LinkString* p1;
LinkString* q ;
while (p->next)
{
q = t->next;
p = p->next;
p1 = p;
while (p1 && q && p1->data == q->data)
{
p1 = p1->next;
q = q->next;
}
if (!q )
return true;
if (!p1)
return false;
}
return false;
}
KMP
-
KMP算法: 每次失配,S串的索引i不動,P串的索引j定位到某個數。T(n)=O(n+m),時間效率明顯提高
-
這裏關鍵是求一個模式串的Next數組
- 我們先把模式串標出序號:
- 接着把模式串所有前綴依次列出來
- 接下來把每一個子串相等的前綴和後綴的最大長度求出,舉個例子”abaab“
- 觀察子串,前後綴ab相同,因此返回2
5.依次類推,我們可以得到每一個子串對應的一組序列
當時這組數據並不是所要求的next數組,可以將其稱爲部分匹配值表,相應c代碼如下
//獲得部分匹配值表
void GetIndexStr(SqString* s,int next [])
{
int i = 1;
int j = 0;
next[0] = 0;
while (i < s->length)
{
if (s->data[i] == s->data[j])
next[i++] = (j++) + 1;
else if ( j ==0 && s->data[i] != s->data[j])
next[i++] = 0;
else
j = next[j - 1];
}
}
- 接着我們可以得到 首字爲 -1 版本的next數組
- 將上述得到的序列向右平移1位(去掉最後一個數),開頭補上 -1 即可
相應c代碼如下
//獲得next數組 :相當於部分匹配值表右移1位,前插 - 1
void GetNextArr(SqString* s, int next[])
{
int i = 0 ;
int j = -1 ;
next[0] = -1;
while (i < s->length - 1)
{
if (j == -1 || s->data[i] == s->data[j])
next[++i] =++ j ;
else j = next[j];
}
}
- 要想得到嚴蔚敏版本的,即將上述序列全部元素+1即可,代碼如下:
void GetNextArrAdd1(SqString* s, int next[])
{
int i = 0;
int j = -1;
next[0] = j+1;
while (i < s->length - 1)
{
if (j == -1 || s->data[i] == s->data[j])
next[++i] = ++j +1;
else
j = next[j] - 1;
}
}
- 獲取到next數組之後,接下來便是KMP算法的主流程
int KMPStr(SqString* s, SqString* t)
{
int next[MAX_SIZE];
int i = 0;
int j = 0;
GetNextArr(t,next);
while (i < s->length && j<t->length)
{
if (j == -1 || s->data[i] == t->data[j])
{
i++;
j++;
}
else j = next[j];
}
if (j >= t->length)
return (i - t->length);
else
return -1;
}
改進KMP
- 按前面的定義可以得到,next[j] = k
- 若Tj=Tk,那麼當Tj和Si不匹配時,也沒必要將Si和Tk進行匹配
- 因此直接將Si和T(next(k))進行匹配
void GetNextValArr(SqString* s, int nextVal[])
{
int i = 0;
int j = -1;
nextVal[0] = -1;
while (i < s->length - 1)
{
if (j == -1 || s->data[i] == s->data[j])
{
i++;
j++;
if (s->data[i] != s->data[j])
nextVal[i] = j;
else nextVal[i] = nextVal[j];
}
else
j = nextVal[j];
}
}