C语言数据结构之模式匹配字符串定位问题

C语言数据结构之模式匹配字符串定位问题

什么是模式匹配字符串定位?

模式匹配字符串定位即在一个文本串中匹配一个模式串,并且返回模式串在文本串中第一次出现的位置。

例如,对于文本串“this is a test string”,我们想要匹配模式串“test”,我们期望得到的结果是第一次出现的位置为10。

KMP算法

算法思路

KMP算法是一种高效的字符串匹配算法。它的核心是利用已经匹配成功的信息,不断调整模式串的起始位置,从而达到减少匹配次数和提高匹配效率的目的。

具体地,我们用一个next数组来保存模式串每个字符在子串中出现时,如果失配该如何继续匹配的信息。并且我们从前缀和后缀比较的角度来得到每个字符在子串中的next值。

然后在匹配过程中,如果匹配失败了,我们利用next数组来更新模式串的起始位置。具体地,我们让模式串“跳过”已经匹配好的前缀,以达到快速匹配的目的。

代码示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define maxn 1000010
char p[maxn], t[maxn];
int next[maxn], lenp, lent;

void get_next() {
    int j = 0, k = -1;
    next[0] = -1;
    while (j < lenp) {
        if (k == -1 || p[j] == p[k]) {
            ++j;
            ++k;
            next[j] = k;
        } else {
            k = next[k];
        }
    }
}

int kmp() {
    int i = 0, j = 0;
    while (i < lent && j < lenp) {
        if (j == -1 || t[i] == p[j]) {
            ++i;
            ++j;
        } else {
            j = next[j];
        }
    }
    if (j == lenp) {
        return i - j;
    } else {
        return -1;
    }
}

int main() {
    scanf("%s %s", t, p);
    lenp = strlen(p);
    lent = strlen(t);
    get_next();
    printf("%d", kmp());
    return 0;
}

算法分析

KMP算法的时间复杂度是O(m+n),其中m和n分别是模式串和文本串的长度。

在实际应用中,通常m远小于n,因此KMP算法可以达到线性级别的时间复杂度,具有较高的效率。

BM算法

算法思路

BM算法是一种查找字符串的优秀算法,它的核心思想是利用规则来跳过尽可能多的匹配。具体地,BM算法分为两个阶段——预处理和匹配。

在预处理阶段,我们需要对模式串p进行预处理,以生成两个跳表,分别是“好后缀”跳表和“坏字符”跳表。

在匹配阶段,我们根据规则决定跳多少步,从而大幅度地减少匹配的次数。具体来说,我们先从右到左地扫描文本串t和模式串p,每当出现不匹配时,我们就利用好后缀和坏字符跳表来计算应该跳过的长度。然后将模式串的起始位置向右移动相应的步数,直到成功匹配模式串或者无法再移动为止。

代码示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define maxn 1000010
#define max(a, b) ((a)>(b)?(a):(b))

char p[maxn], t[maxn];
int lenp, lent, badchar[128], suffix[maxn], p_mxl[maxn];

void pre_badchar() {
    int l = strlen(p);
    for (int i = 0; i < l; i++) {
        badchar[p[i]] = i;
    }
}

void pre_suffix() {
    int l = strlen(p);
    suffix[l - 1] = l;
    int j = l - 1;
    for (int i = l - 2; i >= 0; i--) {
        if (j < i || suffix[l - j + i - 1] >= j - i) {
            if (j < i) {
                j = i;
            }
            while (j >= 0 && p[j] == p[l - 1 - i + j]) {
                --j;
            }
            suffix[i] = j - i;
        } else {
            suffix[i] = suffix[l - j + i - 1];
        }
    }
}

void pre_p_mxl() {
    int l = strlen(p);
    memset(p_mxl, 0, sizeof(p_mxl));
    for (int i = 0; i < l; i++) {
        int j = suffix[i];
        if (j == i + 1) {
            p_mxl[i] = j;
        } else {
            p_mxl[i] = max(p_mxl[i + 1] - 1, j);
        }
    }
}

int bm() {
    int i = 0, j;
    while (i <= lent - lenp) {
        for (j = lenp - 1; j >= 0 && p[j] == t[i + j]; --j);
        if (j < 0) {
            return i;
        } else {
            i += max(p_mxl[j], j - badchar[t[i + j]]);
        }
    }
    return -1;
}

int main() {
    scanf("%s %s", t, p);
    lenp = strlen(p);
    lent = strlen(t);
    pre_badchar();
    pre_suffix();
    pre_p_mxl();
    printf("%d", bm());
    return 0;
}

算法分析

BM算法是一种高效的字符串匹配算法。一般情况下,BM算法的效率比KMP算法高。

在实际应用中,BM算法的最坏时间复杂度是O(mn),但在大多数情况下,BM算法能够获得O(m/n)的时间复杂度。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构之模式匹配字符串定位问题 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • C语言详细分析结构体的内存对齐规则

    C语言详细分析结构体的内存对齐规则 1. 什么是内存对齐 在计算机内存中,每个数据都需要分配一定的内存空间存储,这些空间的大小不一定相同。内存对齐就是要求每个数据按照某个规则,分配其所需的内存空间。 在C语言中,结构体是一种复合数据类型,由多个数据成员组成。结构体的数据成员排列顺序、数据类型均可能不同,因此需要内存对齐来规定内存空间的分配。 2. C语言中结…

    数据结构 2023年5月17日
    00
  • GPS北斗卫星时间同步系统助力电力自动化网络系统

    GPS北斗卫星时间同步系统助力电力自动化网络系统 GPS北斗卫星时间同步系统助力电力自动化网络系统 京准电子官微——ahjzsz 前言 近几年来,随着电力自动化水平的提高,在电力中计算机监控系统、微机保护装置、微机故障录波装置以及各类数据管理机得到了广泛的应用,而这些自动装置的配合工作需要有一个精确统一的时间。当电力系统发生故障时,既可实现全站各系统在统一时…

    算法与数据结构 2023年5月8日
    00
  • Redis数据结构原理浅析

    Redis数据结构原理浅析 Redis是一种高性能键值型数据库,支持多种数据结构,包括字符串、哈希表、列表、集合、有序集合等。本文将对Redis各种数据结构的原理进行浅析。 字符串 Redis中的字符串数据结构不仅可以存储普通的字符,还可以存储整数和浮点数。字符串的最大长度为512MB。字符串结构的底层实现是从一个内存块开始存储的,该内存块的大小为实际存储的…

    数据结构 2023年5月17日
    00
  • Python数据结构与算法的双端队列详解

    Python数据结构与算法的双端队列详解 双端队列(deque)是一种具有队列和栈的性质的数据结构。与队列和栈不同的是双端队列允许从两端添加和删除元素。Python语言中内置了deque模块,使得在实现双端队列时更加方便快捷。 1.双端队列基本操作 from collections import deque # 创建双端队列 d = deque() # 在队…

    数据结构 2023年5月17日
    00
  • Java数据结构之循环队列简单定义与用法示例

    Java数据结构之循环队列简单定义与用法示例 什么是循环队列? 循环队列是一种数据结构,它具有先进先出(FIFO)的特点,即最先进队列的元素总是被最先取出。不同于普通队列,循环队列的尾指针指向数组的头部,因此可以实现循环利用数组空间,提高存储空间的利用率,避免因队列的操作大量移动数组元素而导致的时间浪费。 循环队列的基本操作 循环队列的基本操作包括:入队、出…

    数据结构 2023年5月17日
    00
  • C++高级数据结构之并查集

    C++高级数据结构之并查集 什么是并查集 并查集(Union Find Set)是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。 并查集定义了如下的三种操作: 1、makeSet(s):建立一个新的并查集,其中包含s个单元素集合。 2、unionSet(x, y):把元素x和元素y所在的集…

    数据结构 2023年5月17日
    00
  • Java数据结构与算法之栈(动力节点Java学院整理)

    Java数据结构与算法之栈攻略 什么是栈? 栈是一种线性结构,属于“先进后出”(Last In First Out,LIFO)的数据结构。它只允许在栈顶进行插入和删除操作。 栈的实现 栈的实现有两种方式: 基于数组实现的顺序栈(ArrayStack) 基于链表实现的链式栈(LinkedStack) 1. 基于数组实现的顺序栈 顺序栈的实现需要一个固定大小的数…

    数据结构 2023年5月17日
    00
  • C++数据结构之链表的创建

    C++中链表的创建一般可分为以下几个步骤: 创建节点结构体 创建链表类,定义私有变量头结点(head)和一些公有方法,如插入、删除和打印链表等 实现链表的插入、删除和打印方法 下面将会对以上每个步骤进行详细讲解。 1. 创建节点结构体 节点结构体包含两个部分,一个是存储数据的变量,另一个是存储指向下一个节点的指针。代码如下: struct Node { in…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部