C 语言| 字符串匹配BF算法与RK算法

简介: 字符串匹配算法最经典的手段是BF算法,字符串匹配即给出一个主串S,根据模式串T中的字符串,找出在主串中第一次出现的位置,这个就是字符串匹配,简而言之即给一个规定的内容T,在大范围S中找到一个与之对应的,且第一次出现的位置。

🌟前言


字符串匹配算法最经典的手段是BF算法,字符串匹配即给出一个主串S,根据模式串T中的字符串,找出在主串中第一次出现的位置,这个就是字符串匹配,简而言之即给一个规定的内容T,在大范围S中找到一个与之对应的,且第一次出现的位置。

网络异常,图片无法展示
|

BF算法


BF算法全称叫BruteForce,如本名一样,BF算法十分简单暴力,对主串和模式串进行逐个字符比较,中文名叫暴力匹配算法或者朴素匹配算法

而BF算法就是完成对模式串的移动,一位一位地往后移,然后从第一个字母开始比较,直到找到三个字母都相等的位置。

代码实现


首先我们先来写几个基本函数

/*生成一个其值等于chars的串T*/
Status StrAssign(String T,char *chars)
{
    int i;
    if(strlen(chars)>MAXSIZE)
        return ERROR;
    else{
        T[0]=strlen(chars);     //T[0]存字符串的长度
        for(i=1;i<=T[0];i++)
            T[i]=*(chars+i-1);
        return OK;
        }
}
/*清除字符串,直接令其长度为0*/
Status ClearString(String S)
{
    S[0]=0;
    return OK;
}
/*打印字符串*/
void StrPrint(String T)
{
    int i;
    for(i=1;i<T[0];i++)
        printf("%c",T[i]);
    printf("\n");
}

下面才是我们真正要开始写的BF算法的代码

先传进一个主串,模式串,然后再来一个pos(pos数值为多少,就代表从主串的第几个字母开始查找)

int Index_BF(String S,String T,int pos){
}

接着呢我们就写while循环,一步一步遍历我们的主串和模式串,分别用i,j变量。这里要注意的是,为了方便,我们默认把S[0]和T[0]存入他们各自的串长,也就是遍历从i=1和j=1开始,这样子也更方便我们书写代码,明确代码遍历到了哪一步

然后在while循环里添加if循环,判断S[i]和T[j]是否相等,相等就移到下一位,继续判断,移动就用i++和j++即可

如果不相等,证明遇到了不相同的字母,就让它俩回溯,让i回到初始位置,然后后移,而j回到1,又从模式串第一位开始判断,详细回溯解析看此代码后面的图解

int Index_BF(String S,String T,int pos){
    //主串索引
    int i = pos;
    //模式串索引
    int j = 1;
    while (i<= S[0] && j<=T[0]){
        //S[0]和T[0]的数值代表他们的长度
        if(S[i] == T[j]){
            i++;
            j++;
        }else{
            //回溯,索引下标更改
            i = i-j+2;
            j = 1;
        }
    }
    if(j>T[0]){
        return i-T[0];
    }
    return -1;
}

if循环实现回溯图解

网络异常,图片无法展示
|

以此时i=3为例,正好判断到了第三位,S[i]和T[j]不相等,此时我们发现i = i -j +1是回到原位

网络异常,图片无法展示
|

那我们让其再+1,即i = i - j +2,就可以使其回到原位后再进一位,接着令j = 1,回到模式串第一位进行S[i-j+2]==T[j]的判断

网络异常,图片无法展示
|

此时i=i-j+2=2,S[2]不等于T[1],又一次执行i = i - j +2,这时的i = 3,j = 1,通过这个循环,一步一步后移,实现了我们的BF算法,真的是简单粗暴,这个代码实现如果不能理解,就多看几遍图解,我相信你会有所收获

网络异常,图片无法展示
|

BF算法的时间复杂度很高,但有一个很好的优点就是:代码实现简单,在实际开发中,简单意味着,不容易出错,满足我们所说的KISS,咳咳,不是那个意思哈,是keep it simple and stupid(doge)

RK算法


RK算法是由两位发明者Rabin和Karp的名字来命名的,这个来历应该很容易理解吧(外国人都喜欢用自己名字命名一个新鲜事物哈哈)

相对于BF算法,RK算法比较的不是字母,而是数字,利用到哈希表这种算法,需要计算出哈希值

拿我们的例题来解释

模式串有三个字母,那我们就把主串分别以三个字母为一组子串,全部分隔出来,转化成我们的哈希值h1,h2,h3······,然后再和模式串比较,与哈希值相同的子串,就是我们要匹配到的,在主串中的位置

网络异常,图片无法展示
|

在这里边我们还可以稍作修改,例如我们没必要把所有子串都转化好,再进行与模式串的比较。为了去掉多余的步骤,我们可以边转化,边比较

假设我们的模式串为dda,此时转完第一个abd,不匹配;接着转第二个bdd,也不匹配;此时转到第三个,哎!是dda了,哈希值和模式串相同,这时我们就节省了后面dab,abc等子串的转化。

此时就有疑问了,我们该怎么把这模式串和拆出来的各个子串换算成哈希值呢?

首先我们先看一下十进制位的数字分解,以三位数为例

网络异常,图片无法展示
|

从上面的步骤看,abc的哈希值就是28,有了这套理论,我们就可以开始实践了

//RK算法
int getIndex_RK(String strOne, String strTwo){
    //1、记录两个字符串的长度
    int lengthOne = strOne[0];
    int lengthTwo = strTwo[0];
    //2、计算模式串的Hash值
    long long twoHashValue = 1;
    for (int i = 1; i <= lengthTwo; i++) {
        int value = strTwo[i] - 'a' + 1;
        twoHashValue *= value;
    }
    //3、依次计算出主串每个子串的Hash值,边计算边比较
    long long oneHashValue = 1;
    for (int i = 1; i <= lengthOne - lengthTwo + 1; i++) {
        if (i == 1) {
            for (int j = 1; j <= lengthTwo; j++) {
                int value = strOne[j] - 'a' + 1;
                oneHashValue *= value;
            }
        }
        else {
            //4、计算新子串的Hash值可以根据旧子串的Hash计算得出,减少重复计算
            int valueOld = (strOne[i - 1] - 'a' + 1);
            int valueNew = (strOne[i + lengthTwo - 1] - 'a' + 1);
            oneHashValue = oneHashValue / valueOld * valueNew;
        }
        //5、Hash值相同需对比一下子串和模式串是否匹配(防止出现哈希冲突),匹配则返回index
        if (oneHashValue == twoHashValue) {
            int isOK = isMatch(strOne, i, strTwo);
            if (isOK == 1) {
                return I;
            }
        }
    }
    //6、如果没有找到匹配的子串,则返回-1
    return -1;
}
//判断Hash值相等的字符串是否相等
int isMatch(String strOne, int index, String strTwo){
    for (int i = 1; i <= strTwo[0]; i++) {
        if (strOne[index + i - 1] != strTwo[i]) {
            return 0;
        }
    }
    return 1;
}
目录
打赏
0
0
0
0
108
分享
相关文章
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
115 15
基于 PHP 语言深度优先搜索算法的局域网网络监控软件研究
在当下数字化时代,局域网作为企业与机构内部信息交互的核心载体,其稳定性与安全性备受关注。局域网网络监控软件随之兴起,成为保障网络正常运转的关键工具。此类软件的高效运行依托于多种数据结构与算法,本文将聚焦深度优先搜索(DFS)算法,探究其在局域网网络监控软件中的应用,并借助 PHP 语言代码示例予以详细阐释。
74 1
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
145 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
266 1
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
75 8
基于 PHP 语言的滑动窗口频率统计算法在公司局域网监控电脑日志分析中的应用研究
在当代企业网络架构中,公司局域网监控电脑系统需实时处理海量终端设备产生的连接日志。每台设备平均每分钟生成 3 至 5 条网络请求记录,这对监控系统的数据处理能力提出了极高要求。传统关系型数据库在应对这种高频写入场景时,性能往往难以令人满意。故而,引入特定的内存数据结构与优化算法成为必然选择。
91 3
|
5月前
|
公司局域网管理系统里的 Go 语言 Bloom Filter 算法,太值得深挖了
本文探讨了如何利用 Go 语言中的 Bloom Filter 算法提升公司局域网管理系统的性能。Bloom Filter 是一种高效的空间节省型数据结构,适用于快速判断元素是否存在于集合中。文中通过具体代码示例展示了如何在 Go 中实现 Bloom Filter,并应用于局域网的 IP 访问控制,显著提高系统响应速度和安全性。随着网络规模扩大和技术进步,持续优化算法和结合其他安全技术将是企业维持网络竞争力的关键。
102 2
公司局域网管理系统里的 Go 语言 Bloom Filter 算法,太值得深挖了
企业监控软件中 Go 语言哈希表算法的应用研究与分析
在数字化时代,企业监控软件对企业的稳定运营至关重要。哈希表(散列表)作为高效的数据结构,广泛应用于企业监控中,如设备状态管理、数据分类和缓存机制。Go 语言中的 map 实现了哈希表,能快速处理海量监控数据,确保实时准确反映设备状态,提升系统性能,助力企业实现智能化管理。
79 3
内网监控管理软件:PHP 语言队列算法揭秘
在数字化办公环境中,内网监控管理软件对企业的稳定运行和信息安全至关重要。本文深入介绍PHP中的队列算法及其在内网监控软件中的应用,包括监控数据收集、任务调度和日志记录等场景,通过代码示例展示其实现方法。队列算法可提高性能、保证数据顺序并实现异步处理,为企业提供高效的安全保障。
68 1

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问