字符串的存儲結構
字符串的存儲結構與線性表相同,也分順序存儲結構和鏈式存儲結構。
字符串的順序存儲結構是用一組地址連續的存儲單元來存儲串中的字符序列的。
BF算法——Brute Force 屬於樸素的模式匹配算法(效率低下):
–有兩個字符串S和T,長度爲N和M。首先S[1]和T[1]比較,若相等,則再比較S[2]和T[2],一直到T[M]爲止;若S[1]和T[1]不等,則T向右移動一個字符的位置,再依次進行比較。
–該算法最壞情況下要進行M*(N-M+1)次比較,時間複雜度爲O(M*N)。
int Index(String S,String T,int pos)
{
int i = pos; //i用於主串S中當前位置下標
int j = 1; //j用於子串中當前位置下標
//0號下標存放字符串的長度
while( i<= S[0] && j <= T[0])
{
if(S[i] == T[i])
{
i++;
j++;
}
else // 若失配則j回溯到第一個元素從新匹配
{
i = i-j+2; // i回溯到上次匹配首位的下一個元素
j = 1;
}
}
if(j >T[0])
{
return i-T[0];
}
else
{
return 0;
}
}
KMP算法
KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發現,因此人們稱它爲克努特——莫里斯——普拉特操作(簡稱KMP算法)。關鍵是利用匹配失敗後的信息,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。
在KMP算法中,對於每一個模式串事先計算出模式串的內部匹配信息,在匹配失敗時最大的移動模式串,以減少匹配次數。
給模式匹配串添加一個k數組(也就是KMP中非著名的next()函數,函數本身包含了模式串的局部匹配信息)。
重點在於next()函數的理解:NEXT數組——當模式匹配串T失配的時候,NEXT數組對應的元素指導應該用T串的哪個元素進行下一輪的匹配。
可以嘗試給出一串模式串驗證得到的next值
如下
T |
5 |
a |
b |
a |
b |
a |
a |
a |
b |
a |
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
next |
|
0 |
1 |
1 |
2 |
3 |
4 |
2 |
2 |
3 |
第一位的next值爲0,第二位的next值爲1,後面求解每一位的next值時,根據前一位進行比較。
void next(String T,int *next)
{
//假設i是後綴下標
//j是前綴下標
int j = 0;
int i = 1;
next[1] = 0;
while(i < T[0])
{
if(j==0 || T[i] == T[j])
{
i++;
j++;
next[i] = j;
}
else
{
//回溯
j = next[j];
}
//前綴是固定的,後綴是相對的
}
}
利用已經部分匹配這個有效信息,保持i指針不回溯,通過修改j指針,讓模式串儘量地移動到有效的位置。
#include<stdio.h>
typedef char* String;
void get_next(String T,int *next)
{
//假設i是後綴下標
//j是前綴下標
int j = 0;
int i = 1;
next[1] = 0;
while(i < T[0])
{
if(j==0 || T[i] == T[j])
{
i++;
j++;
next[i] = j;
}
else
{
//回溯
j = next[j];
}
//前綴是固定的,後綴是相對的
}
}
//返回子串T在主串S第pos個字符之後的位置
//若不存在,則返回0
int Index_KMP(String S,String T,int pos)
{
int i = pos;
int j = 1;
int next[255];
get_next(T , next);
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];
//匹配成功,返回位置
}
else
{
return 0;
}
}
int main()
{
return 0;
}