鱼C论坛

 找回密码
 立即注册
查看: 3125|回复: 23

[学习笔记] KMP算法的实现

[复制链接]
回帖奖励 178 鱼币 回复本帖可获得 2 鱼币奖励! 每人限 1 次(中奖概率 50%)
发表于 2024-5-13 20:12:26 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. //给char * 起名为String
  4. typedef char* String;

  5. //定义一个结构体,str存储字符串,cap存储字符串的长度
  6. typedef struct
  7. {
  8.         char str[255];
  9.         int cap;
  10. }Str;

  11. //获取next数组,这个是KMP算法的灵魂
  12. void get_next(Str *T, int *next )
  13. {
  14.         int j = 0;
  15.         int i = 1;
  16.         next[1] = 0;
  17.         
  18.         while( i < T->str[0] )   //当循环次数超过字符串的长度的时候退出循环
  19.         {
  20.                 if( 0 == j || T->str[i] == T->str[j] )
  21.                 {
  22.                         i++;
  23.                         j++;
  24.                         if( T->str[i] != T->str[j] )    //改进后的算法
  25.                         {
  26.                                 next[i] = j;
  27.                         }
  28.                         else
  29.                         {
  30.                                 next[i] = next[j];
  31.                         }
  32.                 }
  33.                 else
  34.                 {
  35.                         j = next[j];
  36.                 }
  37.         }
  38. }

  39. // 返回子串T在主串S第pos个字符之后的位置
  40. // 若不存在,则返回0
  41. int Index_KMP( Str *S, Str *T, int pos )
  42. {
  43.         int i = pos;
  44.         int j = 1;
  45.         int next[255];
  46.         
  47.         get_next( T, next );
  48.         
  49.         while( i <= S->cap && j <= T->cap)
  50.         {
  51.         //增加判断,防止特殊情况发生
  52.                 if( 0 == j || S->str[i] == T->str[j] )
  53.                 {
  54.                         i++;
  55.                         j++;
  56.                 }
  57.                 else
  58.                 {
  59.                         j = next[j];
  60.                 }
  61.         }
  62.         
  63.         if( j > T->cap )
  64.         {
  65.                 return i - T->cap;
  66.         }
  67.         else
  68.         {
  69.                 return 0;
  70.         }
  71. }

  72. //创建存储容量和字符串的结构,这里需要改变结构体的内容,所以传入指向指针的指针
  73. void CreateStr(Str **S)
  74. {
  75.         *S = (Str *)malloc(sizeof (Str));
  76.         if (!S)
  77.         {
  78.                 perror("INIT:malloc");
  79.                 exit(EXIT_FAILURE);
  80.         }
  81.         
  82.         printf("请输入一个字符串,输入回车结束:");
  83.         char ch;
  84.         int i = 0;
  85.         
  86.         while ((ch = getchar()) != '\n')
  87.         {
  88.                 (*S)->str[i++] = ch;     //后置++,先赋值,后++
  89.         }
  90.         //这里i相当与字符串的长度
  91.         (*S)->cap = i;
  92.         
  93. }

  94. int main(void)
  95. {
  96.         Str *S = NULL;
  97.         Str *T = NULL;
  98.         int pos = 1;
  99.         int status = 0;
  100.         
  101.         CreateStr(&S);
  102.         CreateStr(&T);
  103.         
  104.         status = Index_KMP(S, T, pos);
  105.         
  106.         if (1 == status)
  107.         {
  108.                 printf("是");
  109.         }
  110.         else
  111.         {
  112.                 printf("否");        
  113.         }
  114.         
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-5-13 20:13:07 | 显示全部楼层
这段代码实现了KMP算法,用来查找子串在主串中的位置。不过代码中有一些错误和不完善的地方,我来帮你解决。

首先,在函数get_next()中,你需要将next定义为数组,而不是整数。next数组存储的是匹配失败时下一次比较的位置,所以它的长度应该与字符串T的长度相同。修改代码如下:

  1. void get_next(Str *T, int *next )
  2. {
  3.         int j = 0;
  4.         int i = 1;
  5.         next[0] = 0; // 初始化next[0]为0
  6.         
  7.         while( i < T->cap )   //修改为cap
  8.         {
  9.                 if( 0 == j || T->str[i-1] == T->str[j-1] ) // 修改为str[i-1]和str[j-1]
  10.                 {
  11.                         i++;
  12.                         j++;
  13.                         if( T->str[i-1] != T->str[j-1] )    //改进后的算法
  14.                         {
  15.                                 next[i] = j;
  16.                         }
  17.                         else
  18.                         {
  19.                                 next[i] = next[j];
  20.                         }
  21.                 }
  22.                 else
  23.                 {
  24.                         j = next[j];
  25.                 }
  26.         }
  27. }
复制代码


接下来,在函数Index_KMP()中,你需要对pos的取值进行判断,保证在合法范围内。修改代码如下:

  1. int Index_KMP( Str *S, Str *T, int pos )
  2. {
  3.         if (pos < 1 || pos > S->cap) {
  4.                 return 0; // pos超出范围,直接返回0
  5.         }
  6.         
  7.         int i = pos;
  8.         int j = 1;
  9.         int next[T->cap];
  10.         
  11.         get_next( T, next );
  12.         
  13.         while( i <= S->cap && j <= T->cap)  // 小于等于号
  14.         {
  15.                 if( j == 0 || S->str[i-1] == T->str[j-1] ) // 修改为str[i-1]和str[j-1]
  16.                 {
  17.                         i++;
  18.                         j++;
  19.                 }
  20.                 else
  21.                 {
  22.                         j = next[j];
  23.                 }
  24.         }
  25.         
  26.         if( j > T->cap )
  27.         {
  28.                 return i - T->cap;
  29.         }
  30.         else
  31.         {
  32.                 return 0;
  33.         }
  34. }
复制代码


最后,在函数CreateStr()中,你没有为字符数组分配内存空间。修改代码如下:

  1. void CreateStr(Str **S)
  2. {
  3.         *S = (Str *)malloc(sizeof (Str));
  4.         if (!(*S))
  5.         {
  6.                 perror("INIT:malloc");
  7.                 exit(EXIT_FAILURE);
  8.         }

  9.         printf("请输入一个字符串,输入回车结束:");

  10.         int size = 10; // 假定初始容量为10
  11.         int length = 0; // 用于记录字符串的长度
  12.         char ch;

  13.         (*S)->str = (char *)malloc(sizeof(char) * size); // 分配初始内存空间

  14.         if (!((*S)->str))
  15.         {
  16.                 perror("INIT:malloc");
  17.                 exit(EXIT_FAILURE);
  18.         }

  19.         while ((ch = getchar()) != '\n')
  20.         {
  21.                 (*S)->str[length] = ch;
  22.                 length++;

  23.                 if (length == size) // 当存储空间不够时,动态扩展内存
  24.                 {
  25.                         size *= 2;
  26.                         (*S)->str = (char *)realloc((*S)->str, sizeof(char) * size);
  27.                         
  28.                         if (!((*S)->str))
  29.                         {
  30.                                 perror("INIT:realloc");
  31.                                 exit(EXIT_FAILURE);
  32.                         }
  33.                 }
  34.         }

  35.         (*S)->cap = length; // 字符串的长度就是数组的大小
  36. }
复制代码


现在,你可以重新运行程序测试KMP算法了。记得在程序结束前,释放动态分配的内存空间,避免内存泄漏。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:25:00 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:25:51 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:26:03 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:26:43 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:26:56 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:27:31 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:28:10 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:28:26 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:28:40 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:29:17 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:29:46 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:30:03 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:30:20 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:30:39 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:31:15 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-5-14 01:32:02 | 显示全部楼层

回帖奖励 +2 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-5-14 07:56:27 | 显示全部楼层
学习了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-5-14 16:20:08 | 显示全部楼层
sdf
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-9 15:02

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表