【数据结构】模式匹配算法

前端之家收集整理的这篇文章主要介绍了【数据结构】模式匹配算法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

模式匹配:子串的定位操作。

模式匹配算法主要有:

(1)朴素的模式匹配算法;

(2)KMP模式匹配算法 (next数组);

(3)改进的KMP模式匹配算法 (nextval数组);

比较:

1,时间复杂度:朴素的模式匹配算法为O((n-m+1)*m),效率很差,KMP算法为O(m+n),大大避免重复遍历情况。

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


结果:

猜你在找的数据结构相关文章