【C++ 实现字符串的模式匹配算法】

前言

本专栏到这期为止,已经依次介绍了顺序表、链表、数组、栈、队列和二叉树这些数据结构的存储方式以及重要的操作实现。接下来,本期将会讲解字符串的存储方式以及应用:字符串的模式匹配算法

正文

1.字符串

字符串简称串,是由零个或多个字符组成的有限序列。一般记为:

  • S = ‘A1A2A3…An’ (n>=0)
    子串: 串中任意多个相连的字符组成的子序列称为该串的子串。
    主串: 包含子串的串称为该字串的主串。

2.存储结构

串的存储结构可以用三种方式表示:

  • 定长顺序存储表示 (类似定长数组)
  • 堆分配存储表示 (动态申请)
  • 块链存储表示 (类似链式存储)

3.串的模式匹配

子串的定位操作通常称为串的模式匹配,它求的是子串(也称为模式串)在主串中的位置。

//定长顺序存储结构
typedef struct SString{
    
    
   int length;
   char ch[255];
   SString(int len,char c[]){
    
    
       length = len;
       int i = 0;
       while(c[i] != '\0')
       {
    
    
           ch[i] = c[i];
           i++;
       }
   }
};

a.简单的模式匹配算法

思想:暴力求解,通过循环比对两个串的元素。若在主串中找到完整子串,返回子串初始下标。反之,返回-1。
最坏时间复杂度为:O(mn) m,n为两个串的长度。

int MyString::IndexSubstr(SString string1, SString string2)
{
    
    
    if(string1.length <=0)
    {
    
    
        return -1;
    }
    int i = 0,j = 0;
    while(i<string1.length && j<string2.length)
    {
    
    
        char _ch1 = string1.ch[i];
        char _ch2 = string2.ch[j];
        if(_ch1 != _ch2)
        {
    
    
            i ++;
            j = 0;
        }
        else
        {
    
    
            i ++;
            j ++;
            if(j == string2.length)
            {
    
    
                return i-string2.length;
            }
        }

    }
    return -1;
}

b.KMP串的模式匹配算法

思想:相对于朴素的模式匹配算法,KMP算法优化了当模式串匹配失败时的处理
朴素的模式匹配算法中,若字串匹配失败,直接将j的指针退回字串的首个元素位置。此时,并未考虑子串中存在重复前缀的情况。
在这里插入图片描述

//计算模式串失配后,应当跳转比较元素下标
std::vector<int> MyString::computeNext(SString pattern) {
    
    
    int m = pattern.length;
    std::vector<int> next(m, 0);
    int i = 1;
    int j = 0;

    while (i < m) {
    
    
        if (pattern.ch[i] == pattern.ch[j]) {
    
    
            j++;
            next[i] = j;
            i++;
        } else {
    
    
            if (j != 0) {
    
    
                j = next[j - 1];
            } else {
    
    
                next[i] = 0;
                i++;
            }
        }
    }

    return next;
}
//KMP算法,将所有与模式串匹配的下标存储动态数组
std::vector<int> MyString::KMP(SString text, SString pattern) {
    
    
    std::vector<int> next = computeNext(pattern);
    std::vector<int> matches;
    int n = text.length;
    int m = pattern.length;
    int i = 0;
    int j = 0;

    while (i < n) {
    
    
        if (pattern.ch[j] == text.ch[i]) {
    
    
            i++;
            j++;
        }

        if (j == m) {
    
    
            matches.push_back(i - j);
            j = next[j - 1];
        } else if (i < n && pattern.ch[j] != text.ch[i]) {
    
    
            if (j != 0) {
    
    
                j = next[j - 1];
            } else {
    
    
                i++;
            }
        }
    }

    return matches;
}

c.KMP算法的优化

针对模式串中出现的连续重复元素,KMP算法中仍然出现对不必要元素的重复访问。对此,我们可以进一步继续优化KMP算法。
后续更新。。。

猜你喜欢

转载自blog.csdn.net/wddkxg/article/details/131520368