菜鸟笔记
提升您的技术认知

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

阅读 : 64

简介:

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 算法来讲更容易实现且速度较快