串的匹配算法--C语言实现
串这种数据结构,使用是比较多的,但是它的一些方法在更高级的语言中,比如Java,Python中封装的比较完整了。在这里,我只写了串中使用最多的匹配算法,即串的定位操作。串的匹配算法常用的两种就是朴素匹配算法和KMP匹配算法。代码亲测,可直接执行。
1 #include<stdio.h> 2 3 /*字符串长度*/ 4 int StringLength(char *L) 5 { 6 int i = 0; //记录位置 7 int count = 0; //计数器,记录长度 8 while(L[i]) //判断当前位置是否为空 9 { 10 count++; //长度加1 11 i++; //计数器加1 12 } 13 return count; //返回长度 14 } 15 16 /*朴素匹配算法*/ 17 int Index(char *S, char *T) //S为主串,T为子串 18 { 19 int Slength = StringLength(S); //获得主串S的长度 20 int Tlength = StringLength(T); //获得子串T的长度 21 int i = 0; //记录主串S当前位置 22 int j = 0; //记录子串T当前位置 23 // int count = 0; 24 printf("朴素匹配算法中j回溯的值为:"); 25 while(i < Slength && j < Tlength) //确保两个字符串的当前位置均小于其长度 26 { 27 // printf("%d ", j); 28 // count++; 29 if(S[i] == T[j]) //判断主串S当前位置与子串T当前位置的字符是否相等 30 { 31 i++; //主串S的当前位置加1(后移) 32 j++; //子串T的当前位置加1(后移) 33 } 34 else //如果两字符串的当前位置字符不等 35 { 36 i = i - j + 1; //主串S的当前位置i回溯到j==0时i位置的下一位置 37 j = 0; //子串T的当前位置j归0 38 } 39 } 40 // printf("\nj共变化了%d次\n", count); 41 //循环比较完毕 42 if(j == Tlength) //判断位置j的数值是否与子串T的长度相等 43 return i - Tlength; //若是,说明搜索成功,返回T在S中出现的首位置 44 else 45 return -1; //若不是,说明T不存在与S中,返回-1 46 } 47 48 /*KMP算法*/ 49 void Get_Next(char *T, int next[]) 50 { 51 int Tlength = StringLength(T); //获得字符串T的长度 52 int i = 0; //T的后缀位置 53 int j = -1; //T的前缀位置 54 next[0] = -1; //next数组的首位赋值为-1 55 while(i < Tlength) //确保后缀位置小于串长 56 { 57 if(j == -1 || T[i] == T[j]) //如果j==-1,说明前缀已经回退到最前方 58 { //如果T[i] == T[j],说明当前前缀与后缀相等 59 i++; //则后缀位置后移一位 60 j++; //前缀位置后移一位 61 next[i] = j; //当前后缀位置的next值为j 62 } 63 else 64 j = next[j]; //否则,j回退(还没完全搞懂回退到哪) 65 } 66 } 67 68 int Index_KMP(char *S, char *T) 69 { 70 int Slength = StringLength(S); //获得主串S的长度 71 int Tlength = StringLength(T); //获得子串T的长度 72 int i = 0; //记录S的当前位置 73 int j = 0; //记录T的当前位置 74 int next[255]; //next数组 75 Get_Next(T, next); //调用Get_Next函数,为next赋值 76 int count = 0; 77 // printf("KMP算法中j回溯的值为:"); 78 while(i < Slength && j < Tlength) 79 { 80 // printf("%d ", j); 81 // count++; 82 if(j == -1 || S[i] == T[j]) //如果j==-1,说明前缀已经回退到最前方 83 { //如果S[i] == T[j],说明主串与子串当前位置字符相等 84 i++; //S的当前位置后移一位 85 j++; //T的当前位置后移一位 86 } 87 else 88 { 89 j = next[j]; //否则,j回退(未弄懂回退到哪) 90 } 91 } 92 // printf("\nj共变化了%d次\n", count); 93 if(j == Tlength) //比较结束,判断j的值是否与T的长度相等 94 return i - Tlength; //若是,返回T在S中出现的开始位置 95 else 96 return -1; //若不是,返回-1 97 } 98 99 /*KMP改进版算法*/ 100 void Get_Next_Val(char *T, int nextVal[]) 101 { 102 int Tlength = StringLength(T); //获得子串T的长度 103 int i = 0; //记录后缀位置 104 int j = -1; //记录前缀位置 105 nextVal[0] = -1; //next数组第一位置赋值为-1 106 while(i < Tlength) 107 { 108 if(j == -1 || T[i] == T[j]) //同上 109 { 110 i++; //同上 111 j++; 112 if(T[i] != T[j]) //如果位置后移一位后的值不相等 113 nextVal[i] = j; //nextVal等于j 114 else //如果相等 115 nextVal[i] = nextVal[j]; //当前后缀位置的nextVal值等于j位置的nextVal的值 116 } 117 else 118 j = nextVal[j]; //同上 119 } 120 } 121 122 int Index_KMP_Val(char *S, char *T) 123 { 124 int Slength = StringLength(S); //获得主串S的长度 125 int Tlength = StringLength(T); //获得子串T的长度 126 int i = 0; //记录S的当前位置 127 int j = 0; //记录T的当前位置 128 int next[255]; //next数组 129 Get_Next_Val(T, next); //调用Get_Next函数,为next赋值 130 int count = 0; 131 printf("KMP_Val算法中j回溯的值为:"); 132 while(i < Slength && j < Tlength) 133 { 134 printf("%d ", j); 135 count++; 136 if(j == -1 || S[i] == T[j]) //如果j==-1,说明前缀已经回退到最前方 137 { //如果S[i] == T[j],说明主串与子串当前位置字符相等 138 i++; //S的当前位置后移一位 139 j++; //T的当前位置后移一位 140 } 141 else 142 { 143 j = next[j]; //否则,j回退(未弄懂回退到哪) 144 } 145 } 146 printf("\nj共变化了%d次\n", count); 147 if(j == Tlength) //比较结束,判断j的值是否与T的长度相等 148 return i - Tlength; //若是,返回T在S中出现的开始位置 149 else 150 return -1; //若不是,返回-1 151 } 152 153 154 155 void main() 156 { 157 char *S = "aaaaaaaaaaaaaaaaaaaaabcde"; 158 char *T = "aaaaaaaaaaaaaaaaaaaaaaaax"; 159 int pos; 160 pos = Index(S, T); 161 if(pos != -1) 162 printf("朴素匹配算法:子串T在主串S的下标为%d的位置上开始出现\n", pos); 163 else 164 printf("朴素匹配算法:子串T不存在与主串S中\n"); 165 printf("---------------------------------------------------------------------\n"); 166 int pos_KMP; 167 pos_KMP = Index_KMP(S, T); 168 if(pos_KMP != -1) 169 printf("KMP匹配算法:子串T在主串S的下标为%d的位置上开始出现\n", pos_KMP); 170 else 171 printf("KMP匹配算法:子串T不存在与主串S中\n"); 172 printf("---------------------------------------------------------------------\n"); 173 int pos_KMP_val; 174 pos_KMP_val = Index_KMP_Val(S, T); 175 if(pos_KMP_val != -1) 176 printf("KMP_Val匹配算法:子串T在主串S的下标为%d的位置上开始出现\n", pos_KMP_val); 177 else 178 printf("KMP_Val匹配算法:子串T不存在与主串S中\n"); 179 }