算法原理剖析介绍:KMP算法原理
package pkg;
public class KMP {
public static void main(String[] args) {
char[] s1={'B','B','C',' ','A','B','D','D','A','B',' ','A','B','C','D','A','B','C','D','A','B','D','E'};
char[] s2={'A','B','C','D','A','B','D'};
CG(s1, s2);
// int k=0;
// for (int i = k; i < 7; i++) {
// k++;
// System.out.println(k); //输出结果为7
// }
// KMP_BF(s2);
KMP(s1,s2);
}
public static void CG(char[] c1,char[] c2){
/**
* 匹配字符串,这个逐位比较还是比较LOW的,因为做了很多无用功,
* 不需要在这个比较,很多位置是可以跳过的,下面就开始讲解KMP
* 部分匹配表 来做 字符匹配
*/
int k=0;
int l=0;
for (int i = 0; i < c1.length;i++ ) {
for (int j =k; j <c2.length ; j++) { //k用来控制字符串c2的比较位
if(c1[i]==c2[j]){
k++;
if(k==1)
l=i; //l用来记录每次重新比较时,字符串c1该比较的位置
break;
}
k=0; //当一次比较失败,c2从新开始
i=l+1; //当一次比较失败,c1从需要比较位置开始,是上次比较位的后一位
l++; // 没刷新一次比较记录标志就要刷新,l是上一次开始的位置,如果这一次又无法匹配
//那么L如果不变的话,将会一直比较上一次比较的位置,我们需要的是c1是移动的
//所以每当L发挥一次作用,L就自动更新到下一个位置
break;
}
if(k==c2.length){
System.out.println("匹配成功");
break;
}
}
}
public static int KMP_BF(char[] c2) {
/**
* 部分匹配值”就是”前缀”和”后缀”的最长的共有元素的长度。以”ABCDABD”为例,
- ”A”的前缀和后缀都为空集,共有元素的长度为0;
- ”AB”的前缀为[A],后缀为[B],共有元素的长度为0;
- ”ABC”的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
- ”ABCD”的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
- ”ABCDA”的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为”A”,长度为1;
- ”ABCDAB”的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为”AB”,长度为2;
- ”ABCDABD”的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。
*/
int[] bf = new int[c2.length];
bf[0] = 0;
String[] cq = new String[c2.length - 1];
String[] ch = new String[c2.length - 1];
//char类型的数据 存放到String类型数组里
//- ”A”的前缀和后缀都为空集,共有元素的长度为0;
for (int i = 0; i < c2.length - 1; i++) { //[A, AB, ABC, ABCD, ABCDA, ABCDAB]
cq[i] = String.valueOf(c2[0]);
for (int j = 1; j <= i; j++) {
cq[i] += c2[j];
}
}
for (int i = 1; i < c2.length; i++) { //[BCDABD, CDABD, DABD, ABD, BD, D]
ch[i - 1] = String.valueOf(c2[i]);
for (int j = i; j < c2.length - 1; j++) {
ch[i - 1] += c2[j + 1];
}
}
int k = 0;
for (int i = 0; i < cq.length; i++) {
if (cq[i].equals(ch[ch.length - i - 1])) {
k = i + 1; //相同字符串的字符个数 与其位置相关
}
}
return k;
}
public static void KMP(char[] c1,char[] c2){
int[] bf=new int[c2.length];
for (int i = 0; i <c2.length; i++) {
char[] c3=new char[i+1];
for (int j = 0; j <=i; j++) { //j<=i i已经做了数组角标处理,j将不再做数组角标处理,否则将损失一位
c3[j]=c2[j];
}
bf[i]=KMP_BF(c3); //部分配置表 已有
// System.out.println(bf[i]);
}
int k=0;
int l=0;
for (int i = 0; i < c1.length;i++ ) {
for (int j =k; j <c2.length ; j++) { //k用来控制字符串c2的比较位
if(c1[i]==c2[j]){
k++;
if(k==1)
l=i; //l用来记录每次重新比较时,字符串c1该比较的位置
break;
}
//KMP算法,移动位数=已匹配的字符数-对应部分的匹配值
if(k>0)
i=l+(k-bf[k-1]);
else
i=l+(k-bf[k]); //进行多次无法判读的规避 l++ ;l++是对多次不匹配,标志位不动的规避
k=0;
l++;
break;
}
if(k==c2.length){
System.out.println("匹配成功");
break;
}
}
}
}