源码:kmp.cpp

// KMP.cpp : Defines the entry point for the console application.
// #include "stdafx.h"
#include <IOSTREAM>
using namespace std; #define BUF_SIZE 100
#define BUF_SIZE_2 200 /************************************************************************/
/* KMP算法 */
/************************************************************************/ //************************************
// Method: Compute next array
// FullName: 计算NEXT数组
// Access: public
// Returns: void
// Qualifier:
// Parameter: char t[] 模式串
// Parameter: int next[] next数组
// Parameter: int length 模式串长度
//************************************
void Calu_Next_Array(char t[], int next[], int length)
{
int j = 0, k = -1; next[0] = -1;
//next[0]使得模式串T与主串S各向前前进一步,-1用作特殊标志
//next数组大小应为模式串T长度
//j循环从0到length-2,共置n-1次值加上next[0]=-1,一共置n次值
while (j < length - 1)
{
if (k == -1 || t[j] == t[k])
{
//假如k=-1,这是第一次情况,且仅会出现一次
//则当k=-1时,有k=0,j=1,next[1]=0,可知next[1]=0也是恒定不变的
//由递推公式可知,初始情况:next[0]=-1,next[1]=0 //******************* 递推公式推导 *******************
//如果是t[j] == t[k],则有:
//【推导:设next[0]...next[j]已经求出,next[j+1]=?】
//记next[j] = k,则可推出t[0 .. k-1]=t[j-k .. j-1]
//又因为t[j] == t[k],则有t[0 .. k]=t[j-k .. j],推出【next[j+1]=k+1】
//又因为next[j] = k,故【j++,k++】
//【结论:若next[0]...next[j]已知,且t[j] == t[k],则可得next[j+1]=next[j]+1】
next[++j] = ++k;
}
else
{
//******************* 递推公式推导 *******************
//由于t[j] <> t[k],记next[j] = k,则可推出t[0 .. k-1]=t[j-k .. j-1]
//由于t[0 .. k-1]=t[j-k .. j-1],则有t[Y .. k-1]=t[j-k+Y .. j-1] (0<=Y<=k-1)
//令next[k] = K,则有t[0 .. K-1]=t[k-K .. k-1],此时令【Y=k-K】
//即有等式【t[Y .. k-1]=t[j-k+Y .. j-1]=t[k-K .. k-1]=t[Y .. k-1]=t[0 .. K-1]】
//即t[j-K .. j-1]=t[0 .. K-1],【next[j]=K=next[k]】
//若下一次t[j] == t[k'] = t[K],由于t[j-K .. j-1]=t[0 .. K-1]且K=next[k],可得t[j-K .. j]=t[0 .. K],即next[j+1]=next[k]+1
//【结论:若next[0]...next[j]已知,且t[j] <> t[k],若t[j] == t[K] == t[next[k]],则有next[j+1]=next[k]+1】
//这里要判定t[j] == t[k']是否成立,故令k=next[k]
k = next[k];
}
}
} // 打印next数组
void Print_Next_Array(int next[], int length)
{
for (int i = 0; i < length; i++)
{
cout << next[i] << ' ';
}
cout << endl;
} // KMP查找
int KMP(char s[], int s_len, char t[], int t_len, int start)
{
if (start >= s_len) return -1; int *next = new int[t_len]; // T字串长度为next数组长度 if (s_len == 0) throw "原始字串不能为空!";
if (t_len == 0) throw "匹配字串不能为空!";
if (t_len > s_len) throw "原始字串比匹配字串短,匹配(替换)失败!"; Calu_Next_Array(t, next, t_len); // 求next数组
Print_Next_Array(next, t_len); int i = start, j = 0; while (i < s_len && j < t_len)
{
if (j == -1 || s[i] == t[j])
{
i++; j++;
}
else
{
j = next[j];
}
} delete[] next; if (j == t_len) // T遍历到末尾
{
return i - j;
} return -1;
} // 替换
void Replace(char s[], char t[], char r[])
{
int s_len = strlen(s);
int t_len = strlen(t);
int r_len = strlen(r); if (s_len + r_len - t_len >= BUF_SIZE_2) throw "缓冲区不足!"; int index = 0; // 起始索引
int location = 0; // 匹配位置
int count = 0; // 替换次数
int delta = t_len - r_len;
int repl_min_len = (t_len <= r_len) ? t_len : r_len; while (true)
{
index = KMP(s, s_len, t, t_len, index);
if (index == -1) break; location = index + delta * count++;
cout << "找到匹配位置: " << location << endl; // 先替换部分
{
for (int i = 0; i < repl_min_len; i++)
{
s[index + i] = r[i];
}
} if (t_len >= r_len)
{
// 已替换完毕,开始左移
char *src = &s[index + t_len];
char *dest = &s[index + repl_min_len];
while (*src != 0 && *dest != 0) *dest++ = *src++;
*dest = 0;
}
else
{
// 先右移,再替换剩下的
char *null_src = &s[index + repl_min_len - 1];
char *src = &s[s_len];
char *dest = &s[s_len + r_len - t_len];
while (src != null_src) *dest-- = *src--; dest = src + 1;
src = &r[t_len];
while (*src != 0) *dest++ = *src++;
} s_len -= delta;
index -= delta;
index++;
} cout << "成功替换" << count << "处" << endl;
cout << "替换结果: " << s << endl << endl;
} int main(int argc, char* argv[])
{
char buf_string[BUF_SIZE_2];
char buf_find[BUF_SIZE];
char buf_replace[BUF_SIZE]; cout << "请输入字符串:" << endl;
cin.getline(buf_string, BUF_SIZE_2 - 1);
cin.sync(); cout << "请输入要被替换的字符串:" << endl;
cin.getline(buf_find, BUF_SIZE - 1);
cin.sync(); cout << "请输入替换后的字符串:" << endl;
cin.getline(buf_replace, BUF_SIZE - 1);
cin.sync(); try
{
Replace(buf_string, buf_find, buf_replace);
}
catch (const char * pstr)
{
cerr << "****** 错误: " << pstr << endl << endl;
} cout << endl; return 0;
}

字符串与模式匹配(一)——KMP算法的更多相关文章

  1. 串的模式匹配和KMP算法

    在对字符串的操作中,我们经常要用到子串的查找功能,我们称子串为模式串,模式串在主串中的查找过程我们成为模式匹配,KMP算法就是一个高效的模式匹配算法.KMP算法是蛮力算法的一种改进,下面我们先来介绍蛮 ...

  2. 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

    之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...

  3. 字符串模式匹配之KMP算法的next数组详解与C++实现

    相信来看next数组如何求解的童鞋已经对KMP算法是怎么回事有了一定的了解,这里就不再赘述,附上一个链接吧:https://www.cnblogs.com/c-cloud/p/3224788.html ...

  4. 【模式匹配】KMP算法的来龙去脉

    1. 引言 字符串匹配是极为常见的一种模式匹配.简单地说,就是判断主串\(T\)中是否出现该模式串\(P\),即\(P\)为\(T\)的子串.特别地,定义主串为\(T[0 \dots n-1]\),模 ...

  5. 串的模式匹配,KMP算法

    串的模式匹配 现考虑一个常用操作,在字符串s(我们称为主串)中的第pos开始处往后查找,看在主串s中有没有和子串p相匹配的的,如果有,则返回字串p第一次出现的位置. 暴力求解 int Index(ch ...

  6. 字符串(2)KMP算法

    给你两个字符串a(len[a]=n),b(len[b]=m),问b是否是a的子串,并且统计b在a中的出现次数,如果我们枚举a从什么位置与匹配,并且验证是否匹配,那么时间复杂度O(nm), 而n和m的范 ...

  7. 子字符串查找之————关于KMP算法你不知道的事

    写在前面: (阅读本文前需要了解KMP算法的基本思路.另外,本着大道至简的思想,本文的所有例子都会做从头到尾的讲解) 作者翻阅了大量网上现有的KMP算法博客,发现广为流传的竟然是一种不完整的KMP算法 ...

  8. 模式匹配的KMP算法详解

    这种由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现的改进的模式匹配算法简称为KMP算法.大概学过信息学的都知道,是个比较难理解的算法,今天特把它搞个彻彻底底明明白白. 注意到这 ...

  9. 模式匹配之Kmp算法

    Kmp: 算法定义借鉴wikipedia: http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm#KMP_ ...

  10. 数据结构之 字符串---字符串匹配(kmp算法)

    串结构练习——字符串匹配 Time Limit: 1000MS Memory limit: 65536K 题目描述   给定两个字符串string1和string2,判断string2是否为strin ...

随机推荐

  1. 51CTO专访淘宝清无:漫谈Nginx服务器与Lua语言

    http://os.51cto.com/art/201112/307610.htm 说到Web服务器,也许你第一时间会想到Apache,也许你会想到Nginx.虽然说Apache依然是Web服务器的老 ...

  2. 。。。珍惜生命,远离Eclipse。。。

    今天上午就这么过去了,我的人生中有这样一个半天,献给了一个叫做Eclipse的家伙!!!今天是周末,我本应该休息的,但是又犯贱了!!!我竟然主动要加班!!!本来是个很不错心情,现在很不开心!早上来做了 ...

  3. boost源码剖析----boost::any

    boost源码剖析----boost::any 有的时候我们需要有一个万能类型来进行一些操作,这时候boost::any就派上用场了. boost::Any testInt(10); int val ...

  4. 2015弱校联盟(1) - I. Travel

    I. Travel Time Limit: 3000ms Memory Limit: 65536KB The country frog lives in has n towns which are c ...

  5. php入门

    最近公司招了几个应届毕业生,他们对前端的了解还挺多,但是对后端的技术一无所知,我觉得,作为一个前端攻城狮,如果你有远大的抱负,就应该雨露均沾... 今天我就跟大家讲一讲PHP最基本的入门,至少别人问起 ...

  6. PetaPoco入门(一)

    1. ORM概括 1.1. ORM简介 ORM 对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的.面向对象的开发方法是当今企业级应 ...

  7. [问题2014A02] 解答一(两次升阶法,由张钧瑞同学、董麒麟同学提供)

    [问题2014A02] 解答一(两次升阶法,由张钧瑞同学.董麒麟同学提供) 将原行列式 \(|A|\) 升阶,考虑如下 \(n+1\) 阶行列式: \[|B|=\begin{vmatrix} 1 &a ...

  8. 开发板A/D转换原理

    A/D转换器(Analog-to-Digital Converter)又叫模/数转换器,即使将模拟信(电压或是电流的形式)转换成数字信号.这种数字信号可让仪表,计算机外设接口或是微处理机来加以操作或是 ...

  9. 使用servlet实现用户注册功能

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  10. Beaglebone Black – 连接 GY-91 MPU9250+BMP280 九轴传感器(1)

    本篇内容为,通过 I2C 配置 GY-91 MPU9250+BMP280 里面的 MPU9250 连接 AK8963 磁感应.两个办法,1)MPU9250 设置 Master Mode 通过 AUX ...