• Sunday 字符串匹配算法(C++实现)


    简介:

    Sunday算法是Daniel M.Sunday于1990年提出的一种字符串模式匹配算法。其核心思想是:在匹配过程中,模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较,它在发现不匹配时,算法能跳过尽可能多的字符以进行下一步的匹配,从而提高了匹配效率。

    思路:

    Sunday 算法 与 KMP 算法 一样是从前往后匹配,在匹配失败时关注的是主串中参加匹配的最末位字符的下一位字符。
    1、如果该字符没有在模式串中出现则直接跳过,即移动位数 = 模式串长度 + 1;
    2、否则,其移动位数 = 模式串长度 - 该字符最右出现的位置(以0开始) = 模式串中该字符最右出现的位置到尾部的距离 + 1。

    代码:

    #include <iostream>
    #include <string>
    #include <cstdio>
    #include <sstream>
    #include <vector>
    
    using namespace std;
    
    int main(){
        
        string source = "Hello world,hello china,hello beijing";
        string part = "beijing";
        
        int index = 0;//主要用来记录每一次的匹配位置
        int i = 0;//每一次新的循环起始位置
        int j,next;//j用来记录子串的遍历位置,next记录下一个起始位置
        while(i < source.length())
        {
            cout<<"Begin,index: "<<i<<" ,char: "<<source[i]<<endl;
            next = i + part.length();
            index = i;
            j = 0;
            if(part[j]!=source[index])
            {
                //重新计算i的下一个位置
                if(next < source.length())
                {
                    int cut = 0;
                    for(int z = 0; z < part.length(); z++)
                    {
                        if(source[next]==part[z])
                        {
                            cut = z;
                        }
                    }
                    if(cut==0 && source[next]!=part[0])
                    {
                        next++;
                    }
                    else
                    {
                        next -= cut;
                    }
                }
                i = next;
                continue;
            }
            else
            {
                while(j<part.length())
                {
                    if(part[j]!=source[index])
                    {
                        //重新计算i的下一个位置
                        if(next < source.length())
                        {
                            int cut = 0;
                            for(int z = 0; z < part.length(); z++)
                            {
                                if(source[next]==part[z])
                                {
                                    cut = z;
                                }
                            }
                            if(cut==0 && source[next]!=part[0])
                            {
                                next++;
                            }
                            else
                            {
                                next -= cut;
                            }
                        }
                        i = next;
                        break;
                    }
                    index++;
                    j++;
                }
                if(j==part.length())
                {
                    break;
                }
            }
        }
        if(j==part.length())
        {
            cout<<"Yes,begin index is "<<index-j<<endl;
        }
        else
        {
            cout<<"No matching"<<endl;
        }
        
        
        return 0;
    }

    运行结果:

    Begin,index: 0 ,char: H
    Begin,index: 8 ,char: r
    Begin,index: 16 ,char: o
    Begin,index: 24 ,char: h
    Begin,index: 30 ,char: b
    Yes,begin index is 30

    分析:

    第一次遍历,H开始:

    Hello world,hello china,hello beijing
    ^
    beijing
    
    H!=b

    Hello world,hello china,hello beijing
    ^      ^next在这里
    beijing
    
    # 由于next没有出现在子串里面,从next下一个的位置,也就是r开始第二轮遍历
    Hello world,hello china,hello beijing
    ^       ^下一轮遍历的位置
    beijing
     

    第二次遍历,r开始:

    Hello world,hello china,hello beijing
            ^      ^next
            beijing
    
    r!=b

    第三次遍历,o开始:

    Hello world,hello china,hello beijing
                    ^      ^next
                    beijing
    
    o!=b

    第四次遍历,h开始:

    Hello world,hello china,hello beijing
                            ^      ^next
                            beijing
    
    h!=b

    next是e,此时,e在子串 "beijing" 里面能查到,所以下一次应该移动 "eijing" 这部分的长度

    第五次遍历,b开始:

    Hello world,hello china,hello beijing
                                  ^
                                  beijing
    
    b==b
    e==e
    j==j
    i==i
    n==n
    g==g

    结束,能够匹配到

    算法的时间复杂度:O(nm)

    由于 Sunday 算法的偏移量比较大,较 KMP 算法来讲更容易实现且速度较快

  • 相关阅读:
    python全栈闯关--16-匿名函数
    python全栈闯关--15-内置函数
    python全栈闯关--14-生成器进阶
    示例库
    MySQL的远程连接
    前后端传输编码方式
    后端接收前端时间参数
    控制器接参的空值问题
    MyBatis模糊查询的几种方式
    MySQL常用函数
  • 原文地址:https://www.cnblogs.com/lyc94620/p/11420092.html
Copyright © 2020-2023  润新知