模式串匹配、KMP算法及其改进(代码)

  1. #include "string.h"
  2. #include "stdio.h"
  3. #include "stdlib.h"
  4. #include "io.h"
  5. #include "math.h"
  6. #include "time.h"
  7. #define OK 1
  8. #define ERROR 0
  9. #define TRUE 1
  10. #define FALSE 0
  11. #define MAXSIZE 100 /* 存储空间初始分配量 */
  12. typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
  13. typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
  14. typedef char String[MAXSIZE + 1]; /* 0号单元存放串的长度 */
  15. /* 生成一个其值等于chars的串T */
  16. Status StrAssign(String T, char *chars)
  17. {
  18. int i;
  19. if (strlen(chars)>MAXSIZE)
  20. return ERROR;
  21. else
  22. {
  23. T[0] = strlen(chars);
  24. for (i = 1; i <= T[0]; i++)
  25. T[i] = *(chars + i - 1);
  26. return OK;
  27. }
  28. }
  29. Status ClearString(String S)
  30. {
  31. S[0] = 0;/* 令串长为零 */
  32. return OK;
  33. }
  34. /* 输出字符串T。 */
  35. void StrPrint(String T)
  36. {
  37. int i;
  38. for (i = 1; i <= T[0]; i++)
  39. printf("%c", T[i]);
  40. printf("\n");
  41. }
  42. /* 输出Next数组值。 */
  43. void NextPrint(int next[], int length)
  44. {
  45. int i;
  46. for (i = 1; i <= length; i++)
  47. printf("%d", next[i]);
  48. printf("\n");
  49. }
  50. /* 返回串的元素个数 */
  51. int StrLength(String S)
  52. {
  53. return S[0];
  54. }
  55. /* 朴素的模式匹配法 */
  56. int Index(String S, String T, int pos)
  57. {
  58. int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
  59. int j = 1; /* j用于子串T中当前位置下标值 */
  60. while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
  61. {
  62. if (S[i] == T[j]) /* 两字母相等则继续 */
  63. {
  64. ++i;
  65. ++j;
  66. }
  67. else /* 指针后退重新开始匹配 */
  68. {
  69. i = i - j + 2; /* i退回到上次匹配首位的下一位 */
  70. j = 1; /* j退回到子串T的首位 */
  71. }
  72. }
  73. if (j > T[0])
  74. return i - T[0];
  75. else
  76. return 0;
  77. }
  78. /* 通过计算返回子串T的next数组。 */
  79. void get_next(String T, int *next)
  80. {
  81. int i, j;
  82. i = 1;
  83. j = 0;
  84. next[1] = 0;
  85. while (i<T[0]) /* 此处T[0]表示串T的长度 */
  86. {
  87. if (j == 0 || T[i] == T[j]) /* T[i]表示后缀的单个字符,T[j]表示前缀的单个字符 */
  88. {
  89. ++i;
  90. ++j;
  91. next[i] = j;
  92. }
  93. else
  94. j = next[j]; /* 若字符不相同,则j值回溯 */
  95. }
  96. }
  97. /* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
  98. /* T非空,1≤pos≤StrLength(S)。 */
  99. int Index_KMP(String S, String T, int pos)
  100. {
  101. int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
  102. int j = 1; /* j用于子串T中当前位置下标值 */
  103. int next[255]; /* 定义一next数组 */
  104. get_next(T, next); /* 对串T作分析,得到next数组 */
  105. while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
  106. {
  107. if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
  108. {
  109. ++i;
  110. ++j;
  111. }
  112. else /* 指针后退重新开始匹配 */
  113. j = next[j];/* j退回合适的位置,i值不变 */
  114. }
  115. if (j > T[0])
  116. return i - T[0];
  117. else
  118. return 0;
  119. }
  120. /* 求模式串T的next函数修正值并存入数组nextval */
  121. void get_nextval(String T, int *nextval)
  122. {
  123. int i, j;
  124. i = 1;
  125. j = 0;
  126. nextval[1] = 0;
  127. while (i<T[0]) /* 此处T[0]表示串T的长度 */
  128. {
  129. if (j == 0 || T[i] == T[j]) /* T[i]表示后缀的单个字符,T[j]表示前缀的单个字符 */
  130. {
  131. ++i;
  132. ++j;
  133. if (T[i] != T[j]) /* 若当前字符与前缀字符不同 */
  134. nextval[i] = j; /* 则当前的j为nextval在i位置的值 */
  135. else
  136. nextval[i] = nextval[j]; /* 如果与前缀字符相同,则将前缀字符的 */
  137. /* nextval值赋值给nextval在i位置的值 */
  138. }
  139. else
  140. j = nextval[j]; /* 若字符不相同,则j值回溯 */
  141. }
  142. }
  143. int Index_KMP1(String S, String T, int pos)
  144. {
  145. int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
  146. int j = 1; /* j用于子串T中当前位置下标值 */
  147. int next[255]; /* 定义一next数组 */
  148. get_nextval(T, next); /* 对串T作分析,得到next数组 */
  149. while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
  150. {
  151. if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
  152. {
  153. ++i;
  154. ++j;
  155. }
  156. else /* 指针后退重新开始匹配 */
  157. j = next[j];/* j退回合适的位置,i值不变 */
  158. }
  159. if (j > T[0])
  160. return i - T[0];
  161. else
  162. return 0;
  163. }
  164. int main()
  165. {
  166. int i, *p;
  167. String s1, s2;
  168. StrAssign(s1, "abcdex");
  169. printf("子串为: ");
  170. StrPrint(s1);
  171. i = StrLength(s1);
  172. p = (int*)malloc((i + 1)*sizeof(int));
  173. get_next(s1, p);
  174. printf("Next为: ");
  175. NextPrint(p, StrLength(s1));
  176. printf("\n");
  177. StrAssign(s1, "abcabx");
  178. printf("子串为: ");
  179. StrPrint(s1);
  180. i = StrLength(s1);
  181. p = (int*)malloc((i + 1)*sizeof(int));
  182. get_next(s1, p);
  183. printf("Next为: ");
  184. NextPrint(p, StrLength(s1));
  185. printf("\n");
  186. StrAssign(s1, "ababaaaba");
  187. printf("子串为: ");
  188. StrPrint(s1);
  189. i = StrLength(s1);
  190. p = (int*)malloc((i + 1)*sizeof(int));
  191. get_next(s1, p);
  192. printf("Next为: ");
  193. NextPrint(p, StrLength(s1));
  194. printf("\n");
  195. StrAssign(s1, "aaaaaaaab");
  196. printf("子串为: ");
  197. StrPrint(s1);
  198. i = StrLength(s1);
  199. p = (int*)malloc((i + 1)*sizeof(int));
  200. get_next(s1, p);
  201. printf("Next为: ");
  202. NextPrint(p, StrLength(s1));
  203. printf("\n");
  204. StrAssign(s1, "ababaaaba");
  205. printf(" 子串为: ");
  206. StrPrint(s1);
  207. i = StrLength(s1);
  208. p = (int*)malloc((i + 1)*sizeof(int));
  209. get_next(s1, p);
  210. printf(" Next为: ");
  211. NextPrint(p, StrLength(s1));
  212. get_nextval(s1, p);
  213. printf("NextVal为: ");
  214. NextPrint(p, StrLength(s1));
  215. printf("\n");
  216. StrAssign(s1, "aaaaaaaab");
  217. printf(" 子串为: ");
  218. StrPrint(s1);
  219. i = StrLength(s1);
  220. p = (int*)malloc((i + 1)*sizeof(int));
  221. get_next(s1, p);
  222. printf(" Next为: ");
  223. NextPrint(p, StrLength(s1));
  224. get_nextval(s1, p);
  225. printf("NextVal为: ");
  226. NextPrint(p, StrLength(s1));
  227. printf("\n");
  228. StrAssign(s1, "00000000000000000000000000000000000000000000000001");
  229. printf("主串为: ");
  230. StrPrint(s1);
  231. StrAssign(s2, "0000000001");
  232. printf("子串为: ");
  233. StrPrint(s2);
  234. printf("\n");
  235. printf("主串和子串在第%d个字符处首次匹配(朴素模式匹配算法)\n", Index(s1, s2, 1));
  236. printf("主串和子串在第%d个字符处首次匹配(KMP算法) \n", Index_KMP(s1, s2, 1));
  237. printf("主串和子串在第%d个字符处首次匹配(KMP改良算法) \n", Index_KMP1(s1, s2, 1));
  238. return 0;
  239. }





posted @ 2015-07-07 12:51  Lucas_1993  阅读(297)  评论(0编辑  收藏  举报