[关闭]
@yanglt7 2018-10-21T15:50:18.000000Z 字数 4469 阅读 873

07_字符串匹配 -- BF算法、KMP算法

数据结构和算法


7.1字符串

7.1.1 定义

7.1.2 字符串的比较

7.1.3 字符串的存储结构

7.2 BF (Brute Force) 算法

  1. #include <stdio.h>
  2. typedef char *String;
  3. //返回子串T在主串S的第pos个字符后(含第pos个位置)第一次出现的位置
  4. //若不存在,则返回-1
  5. //采用BF算法,这里的位置全部以从1开始计算为准,其中T非空,1<=pos<=T[0]
  6. int Index_BF( String S, String T , int pos )
  7. {
  8. int i = pos; //主串当前正待比较的位置,初始为pos
  9. int j = 1; //子串当前正待比较的位置,初始为1
  10. while( i <= S[0] && j <= T[0] )
  11. {
  12. if( S[i] == T[j] ) //如果当前字符相同,则继续向下比较
  13. {
  14. i++;
  15. j++;
  16. }
  17. else //如果当前字符不同,则i和j回退,重新进行匹配
  18. {
  19. i = i-j+2;
  20. j = 1;
  21. }
  22. }
  23. if( j > T[0] )
  24. {
  25. return i - T[0];
  26. }
  27. else
  28. {
  29. return -1;
  30. }
  31. }
  32. int main()
  33. {
  34. char S[255];
  35. char T[255];
  36. char c, e;
  37. int n = 1;
  38. int k = 0;
  39. int pos;
  40. printf("请输入主串: ,并以#作为结束标志!\n");
  41. scanf("%c", &c);
  42. while( c != '#' )
  43. {
  44. S[n++] = c;
  45. S[n] = '\0';
  46. scanf("%c", &c);
  47. }
  48. S[0] = n-1;
  49. printf("请输入子串: ,并以#作为结束标志!\n");
  50. scanf("%c", &e);
  51. while( e != '#' )
  52. {
  53. T[k++] = e;
  54. T[k] = '\0';
  55. scanf("%c", &e);
  56. }
  57. T[0] = k-1;
  58. printf("请输入主串中开始进行匹配的位置(首字符位置为1):\n");
  59. scanf("%d", &pos);
  60. int result = Index_BF( S, T, pos );
  61. if( result != -1 )
  62. {
  63. printf("主串与子串在主串的第%d个字符(首字符的位置为1)处首次匹配", result);
  64. }
  65. else
  66. {
  67. printf("无匹配子串\n");
  68. }
  69. return 0;
  70. }

7.3 KMP算法

7.3.1 回溯

7.3.2 思路启发

S 14 I l o v e F i s h C . c o m
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
T 5 I l o v x
j 0 1 2 3 4 5

- 思路启发二

S 13 w w w . F i s h C . c o m
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13
T 3 w w .
j 0 1 2 3

- 思路启发三

S 12 b b s b b s . F i s h C
i 0 1 2 3 4 5 6 7 8 9 10 11 12
T 6 b b s b b c
j 0 1 2 3 4 5 6

- 思路启发四

S 8 s s s s s s s x
i 0 1 2 3 4 5 6 7 8
T 5 s s s s b
j 0 1 2 3 4 5

7.3.3 k数组

S 14 I l o v e F i s h C . c o m
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
T 5 I l o v x
j 0 1 2 3 4 5
k 0 1 1 1 1
S 13 w w w . F i s h C . c o m
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13
T 3 w w .
j 0 1 2 3
k 0 1 2
S 12 b b s b b s . F i s h C
i 0 1 2 3 4 5 6 7 8 9 10 11 12
T 6 b b s b b c
j 0 1 2 3 4 5 6
k 0 1 2 1 2 3
S 8 s s s s s s s x
i 0 1 2 3 4 5 6 7 8
T 5 s s s s b
j 0 1 2 3 4 5
k 0 1 2 3 4

7.4 KMP算法之next数组代码原理分析

T 9 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

i (后缀) = 1 2 。3 4 5 6 7 。8 9
j (前缀) = 0 1 0 1 2 3 4 2 1 2 3

next数组:当模式匹配串T失配的时候,next数组对应的元素指导应该用T串的哪个元素进行下一轮的匹配。

  1. void get_next( String T, int *next )
  2. {
  3. j = 0;
  4. i = 1;
  5. next[1] = 0;
  6. while( i < T[0] )
  7. {
  8. if( 0 == j || T[i] == T[j] )
  9. {
  10. i++;
  11. j++;
  12. next[i] = j;
  13. }
  14. else
  15. {
  16. //j回溯
  17. j = next[j];
  18. }
  19. }
  20. //因为前缀是固定的,后缀是相对的
  21. }

7.5 KMP算法之实现及优化

7.5.1 获取next数组的代码实现

  1. #include <stdio.h>
  2. typedef char * String;
  3. void get_next( String T, int *next )
  4. {
  5. int j = 0;
  6. int i = 1;
  7. next[1] = 0;
  8. while( i < T[0] )
  9. {
  10. if( 0 == j || T[i] == T[j] )
  11. {
  12. i++;
  13. j++;
  14. next[i] = j;
  15. }
  16. else
  17. {
  18. //j回溯
  19. j = next[j];
  20. }
  21. }
  22. //因为前缀是固定的,后缀是相对的
  23. }
  24. int main()
  25. {
  26. char str[255] = " ababaaaba";
  27. int next[255];
  28. int i = 1;
  29. str[0] = 9;
  30. get_next( str, next );
  31. for( i=1; i < 10; i++ )
  32. {
  33. printf("%d ", next[i]);
  34. }
  35. return 0;
  36. }
  1. #include <stdio.h>
  2. typedef char * String;
  3. void get_next( String T, int *next )
  4. {
  5. int j = 0;
  6. int i = 1;
  7. next[1] = 0;
  8. while( i < T[0] )
  9. {
  10. if( 0 == j || T[i] == T[j] )
  11. {
  12. i++;
  13. j++;
  14. next[i] = j;
  15. }
  16. else
  17. {
  18. //j回溯
  19. j = next[j];
  20. }
  21. }
  22. //因为前缀是固定的,后缀是相对的
  23. }
  24. int main()
  25. {
  26. char T[255];
  27. int next[255];
  28. int i = 1;
  29. int n = 1;
  30. char c;
  31. printf("请输入需要获取next数组的字符串:,并以#作为结束标志!\n");
  32. scanf("%c", &c);
  33. while( c != '#' )
  34. {
  35. T[n++] = c;
  36. T[n] = '\0';
  37. scanf("%c", &c);
  38. }
  39. T[0] = n;
  40. get_next( T, next );
  41. for( i=1; i < T[0]; i++ )
  42. {
  43. printf("%d ", next[i]);
  44. }
  45. return 0;
  46. }

7.5.2 KMP算法匹配主串和子串

  1. #include <stdio.h>
  2. typedef char * String;
  3. void get_next( String T, int *next )
  4. {
  5. int j = 0;
  6. int i = 1;
  7. next[1] = 0;
  8. while( i < T[0] )
  9. {
  10. if( 0 == j || T[i] == T[j] )
  11. {
  12. i++;
  13. j++;
  14. if( T[i] != T[j] )
  15. {
  16. next[i] = j;
  17. }
  18. else
  19. {
  20. next[i] = next[j];
  21. }
  22. }
  23. else
  24. {
  25. //j回溯
  26. j = next[j];
  27. }
  28. }
  29. //因为前缀是固定的,后缀是相对的
  30. }
  31. //返回子串T在主串S第pos个字符的位置
  32. //若不存在,则返回-1
  33. int Index_KMP( String S, String T, int pos )
  34. {
  35. int i = pos;
  36. int j = 1;
  37. int next[255];
  38. get_next( T, next );
  39. while( i <= S[0] && j <= T[0] )
  40. {
  41. if( 0 == j || S[i] == T[j] )
  42. {
  43. i++;
  44. j++;
  45. }
  46. else
  47. {
  48. j = next[j];
  49. }
  50. }
  51. if( j > T[0] )
  52. {
  53. return i - T[0];
  54. printf("%d ", i - T[0]);
  55. }
  56. else
  57. {
  58. return -1;
  59. }
  60. }
  61. int main()
  62. {
  63. char S[255] ;
  64. char T[255] ;
  65. int next[255];
  66. int n = 1;
  67. int k = 0;
  68. int pos;
  69. char c,e;
  70. printf("请输入主串: ,并以#作为结束标志!\n") ;
  71. scanf("%c", &c);
  72. while( c != '#' )
  73. {
  74. S[n++] = c;
  75. S[n] = '\0';
  76. scanf("%c", &c);
  77. }
  78. S[0] = n-1;
  79. printf("S[0]=%d", S[0]);
  80. printf("请输入子串: ,并以#作为结束标志!\n");
  81. scanf("%c", &e);
  82. while( e != '#' )
  83. {
  84. T[k++] = e;
  85. T[k] = '\0';
  86. scanf("%c", &e);
  87. }
  88. T[0] = k-1;
  89. printf("T[0]=%d", T[0]);
  90. printf("请输入主串中开始进行匹配的位置(首字符位置为1):\n");
  91. scanf("%d", &pos);
  92. int result = Index_KMP( S, T, pos );
  93. if( result != -1 )
  94. {
  95. printf("主串与子串在主串的第%d个字符(首字符的位置为1)处首次匹配", result);
  96. }
  97. else
  98. {
  99. printf("无匹配子串\n");
  100. }
  101. return 0;
  102. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注