泛型KMP算法

简介: 当我们需要从一个字符串(主串)中寻找一个模式串(子串)时,使用KMP算法可以极大地提升效率。KMP是一个高效的字符串匹配算法,它巧妙的消除了在匹配的过程中指针回溯的问题,关于KMP算法的更多介绍,可以参考这里。

当我们需要从一个字符串(主串)中寻找一个模式串(子串)时,使用KMP算法可以极大地提升效率。KMP是一个高效的字符串匹配算法,它巧妙的消除了在匹配的过程中指针回溯的问题,关于KMP算法的更多介绍,可以参考这里

原始的KMP算法适用的对象是字符串的匹配搜索,其实针对任意类型的串(实际上就是一个数组)的子串搜索,都可以使用KMP算法。比如,我们可能需要在byte[]中查找一个特定的字节数组,这同样可以使用KMP算法来提升匹配性能。为此,我实现了泛型的KMP算法,使之可以应用于任意类型的串匹配。下面是该算法的完整实现。

    /// <summary>
    /// 泛型KMP算法。
    /// zhuweisky 2013.06.06
    /// </summary>
    public static class GenericKMP
    {
        /// <summary>
        /// Next函数。 
        /// </summary>
        /// <param name="pattern">模式串</param>
        /// <returns>回溯函数</returns>
        public static int[] Next<T>(T[] pattern) where T : IEquatable<T>
        {
            int[] nextFunction = new int[pattern.Length];
            nextFunction[0] = -1;
            if (pattern.Length < 2) 
            {
                return nextFunction;
            }

            nextFunction[1] = 0; 
            int computingIndex = 2;  
            int tempIndex = 0;  
            while (computingIndex < pattern.Length)   
            { 
                if (pattern[computingIndex - 1].Equals(pattern[tempIndex]))   
                {  
                    nextFunction[computingIndex++] = ++tempIndex;
                }
                else
                {   
                    tempIndex = nextFunction[tempIndex];
                    if (tempIndex == -1)    
                    {   
                        nextFunction[computingIndex++] = ++tempIndex;
                    }
                }
            }
            return nextFunction;
        }

        /// <summary>
        /// KMP计算
        /// </summary>
        /// <param name="source">主串</param>       
        /// <param name="pattern">模式串</param>
        /// <returns>匹配的第一个元素的索引。-1表示没有匹配</returns>
        public static int ExecuteKMP<T>(T[] source, T[] pattern) where T : IEquatable<T>
        {
            int[] next = Next(pattern);
            return ExecuteKMP(source, 0, source.Length, pattern, next);
        }

        /// <summary>
        /// KMP计算
        /// </summary>
        /// <param name="source">主串</param>
        /// <param name="sourceOffset">主串起始偏移</param>
        /// <param name="sourceCount">被查找的主串的元素个数</param>
        /// <param name="pattern">模式串</param>
        /// <returns>匹配的第一个元素的索引。-1表示没有匹配</returns>
        public static int ExecuteKMP<T>(T[] source, int sourceOffset, int sourceCount, T[] pattern) where T : IEquatable<T>
        {
            int[] next = Next(pattern);
            return ExecuteKMP(source, sourceOffset, sourceCount, pattern, next);
        }

        /// <summary>
        /// KMP计算
        /// </summary>
        /// <param name="source">主串</param>       
        /// <param name="pattern">模式串</param>
        /// <param name="next">回溯函数</param>
        /// <returns>匹配的第一个元素的索引。-1表示没有匹配</returns>
        public static int ExecuteKMP<T>(T[] source, T[] pattern, int[] next) where T : IEquatable<T>
        {            
            return ExecuteKMP(source, 0, source.Length, pattern, next);
        }

        /// <summary>
        /// KMP计算
        /// </summary>
        /// <param name="source">主串</param>
        /// <param name="sourceOffset">主串起始偏移</param>
        /// <param name="sourceCount">被查找的主串的元素个数</param>
        /// <param name="pattern">模式串</param>
        /// <param name="next">回溯函数</param>
        /// <returns>匹配的第一个元素的索引。-1表示没有匹配</returns>
        public static int ExecuteKMP<T>(T[] source, int sourceOffset, int sourceCount, T[] pattern, int[] next) where T : IEquatable<T>
        {
            int sourceIndex = sourceOffset;  
            int patternIndex = 0;             
            while (patternIndex < pattern.Length && sourceIndex < sourceOffset + sourceCount)
            {
                if (source[sourceIndex].Equals(pattern[patternIndex]))   
                {
                    sourceIndex++;
                    patternIndex++;
                }
                else
                {
                    patternIndex = next[patternIndex];
                    if (patternIndex == -1)
                    {
                        sourceIndex++;
                        patternIndex++;
                    }
                }
            }         
            return patternIndex < pattern.Length ? -1 : sourceIndex - patternIndex;
        }
    } 

说明:

(1)串中的每个元素必须能够被比较是否相等,所以,泛型T必须实现IEquatable接口。

(2)之所以将Next函数暴露为public,是为了在外部可以缓存回溯函数,以供多次使用。因为,我们可能经常会在不同的主串中搜索同一个模式串。

(3)如果要将GenericKMP应用于字符串的匹配搜索,可以先将字符串转换为字符数组,再调用GenericKMP算法。就像下面这样:

    string source = "..............";
    string pattern = "*****";
    int index = GenericKMP.ExecuteKMP<char>(source.ToCharArray(),pattern.ToCharArray()) ;

 

目录
相关文章
|
4月前
|
存储 机器学习/深度学习 算法
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty 敏感词
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty 敏感词
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty  敏感词
|
3月前
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
80 0
|
11月前
|
算法
第四章 KMP算法理论基础
第四章 KMP算法理论基础
148 0
|
11月前
|
算法
KMP算法
KMP算法
103 0
|
算法 C++
A : DS串应用–KMP算法
这篇文章提供了KMP算法的C++实现,包括计算模式串的next数组和在主串中查找模式串位置的函数,用于演示KMP算法的基本应用。
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
299 1
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
算法
KMP算法
KMP算法
87 0
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
人工智能 算法 BI
一篇文章讲明白KMP算法(俗称看毛片算法)
一篇文章讲明白KMP算法(俗称看毛片算法)
246 0
|
算法 Java
Java数据结构与算法:字符串匹配算法之KMP算法
Java数据结构与算法:字符串匹配算法之KMP算法

热门文章

最新文章