zoukankan      html  css  js  c++  java
  • 彩色打印KMP匹配过程

    前言:只是为了加深自己对面试题的领悟力,如果有做的错的,请指出,感激

    术语定义:字符串"abc"和字符串"abcadcabc",如果我们想要求出字符串"abc"在字符串"abcadcabc"中第一次出现的位置,称"abc"是匹配字符串,称"abcadcabc"是被匹配字符串

    KMP算法的原理,网上有很多文章给出了详细的解释,http://www.ruanyifeng.com/blog/2013/05/Knuth–Morris–Pratt_algorithm.html 这篇是阮一峰从字符串前缀和后缀的角度,给去KMP算法的解释,文章写的很好图文并茂,可以帮助大家理解。

    http://www.ics.uci.edu/~eppstein/161/960227.html 这篇文章是从有限自动机的角度去解释,当匹配字符串中某个字符串不匹配时,字符串的比较情况,匹配字符串是"nano",见下图:

    文章还给出了算法的详细解释和C++代码实现,有兴趣,可以学习一下。http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm 这个是维基百科关于KMP算法的解释,其中有一个额外连接可以动态的展示KMP的匹配过程,是一个Applet的程序,见 http://people.cs.pitt.edu/~kirk/cs1501/animations/String.html 。效果见下图

     

    效果十分的好,可惜我Java不行,而且人家不开源,也尝试下载他们的.class文件,然后通过反编译获取源代码,可以只能找到部分代码,部分.class文件怎么也找不到,于是我就想仿照这个Applet,写一个类似的C#控制台程序出来。

    还好憋出来了,见下图。

     

     

    先总结教训和经验,再介绍相关代码。

    1我开始设计时,我总是想把每一行抽象出来,因为左边一行是左边是要输出内容的解释或者名字,右边是输出的内容,但是在实际过程中需要考虑左边边距的问题,而且输出的内容之间是存在一定的关联的,反正最后一直没有实现。经验和教训是:不要老想着这么优化那么优化,先写出来再说

    2实现过程中也没有什么难点,主要是:在最后一行匹配的时候,显示Searching Info的时候通过控制好控制台的光标,按照不同的颜色显示已经匹配的字符串。主要通过PrintSeahingInfo(int skip,int matching)这个函数实现。 

            /// <summary>
            /// 每次搜索,都调用该函数,显示已经匹配了哪些字符
            /// </summary>
            /// <param name="skip">需要跳过的位置</param>
            /// <param name="matching">已经匹配的字符,匹配的字符用红色显示</param>
            private void PrintSeahingInfo(int skip,int matching) 

    3算法实现的比较不好,基本上控制台每行输出对应一个函数,通过线程Sleep 1秒钟,动态显示匹配过程。

    下面是实现代码:

    public class ColorFulKMP 代码
        public class ColorFullKMP 
        {
            char[] pattern;
            char[] seachingString;
            int [] overlap;
            //美观程序界面,与左边的距离
            private readonly int INCREMENT = 5;
            private readonly int INCREMENT_2 = 5*3;
            private readonly int INCREMENT_3 = 5 * 6;  
            //打印标题,程序中红字部分
            private void PrintTitle(string title)
            {
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Red;
                Console.CursorTop = Console.CursorTop + 1;
                Console.CursorLeft = INCREMENT;
                Console.Write(title);
                Console.ForegroundColor = frontColor;
            }
            //打印子pattern和seachingString
            private void PrintString(string strName,char []strValue)
            {
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Blue;
                Console.CursorTop = Console.CursorTop + 1;
                Console.CursorLeft = INCREMENT_2;
                Console.Write(strName);
                Console.CursorLeft = INCREMENT_3;
                for (int i = 0; i < strValue.Length; i++)
                {
                    Console.Write(strValue[i]);
                    Console.Write(' ');
                }
                Console.ForegroundColor = frontColor;
            }
            //对外提供的接口
            public void Binding(string sstring,string strPattern) 
            {
                seachingString=sstring.ToCharArray();
                pattern = strPattern.ToCharArray();
            }
            public ColorFullKMP() 
            {
                string temp = "huhubhuhuhuhaubu";
                seachingString = temp.ToCharArray();
                temp = "huhuhau";
                pattern = temp.ToCharArray();
            }
            //KMP算法中实现get_next部分,初始化overlap
            private void KmpOverlap()
            {
                overlap=new int [pattern.Length+1];
                overlap[0] = -1;
                for (int i = 0; i < pattern.Length; i++)
                {
                    overlap[i + 1] = overlap[i] + 1;
                    while (overlap[i + 1] > 0 &&
                        pattern[i] != pattern[overlap[i + 1] - 1])
                        overlap[i + 1] = overlap[overlap[i + 1] - 1] + 1;
                }
            }
            private void PrintAlgorithmInfo() 
            {
                PrintTitle("Algorithm Information:");
                PrintIndex();
                PrintString("Pattern:",pattern);
                PrintJump();
            }
            private void PrintIndex() 
            {
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Blue;
                Console.CursorTop = Console.CursorTop + 1;
                Console.CursorLeft = INCREMENT_2;
                Console.Write("Index:");
                Console.CursorLeft = INCREMENT_3;
                for (int i = 0; i < pattern.Length; i++) 
                {
                    Console.Write(i);
                    Console.Write(' ');
                }
                    Console.ForegroundColor = frontColor;
            }
            private void PrintJump() 
            {
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Blue;
                Console.CursorTop = Console.CursorTop + 1;
                Console.CursorLeft = INCREMENT_2;
                Console.Write("Jump Info:");
                Console.CursorLeft = INCREMENT_3-1;
                for (int i = 0; i < overlap.Length-1; i++)
                {
                    Console.Write(overlap[i]);
                    Console.Write(' ');
                }
                Console.ForegroundColor = frontColor;
            }
            private void PrintSeahingInfo() 
            {
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Blue;
                Console.CursorTop = Console.CursorTop + 1;
                Console.CursorLeft = INCREMENT_2;
                Console.Write("Seahing Info:");
                Console.ForegroundColor = frontColor;
                Console.CursorLeft = INCREMENT_3;
            }
            /*
             * 每次搜索,都调用该函数,显示已经匹配了哪些字符
             */
            /// <summary>
            /// 每次搜索,都调用该函数,显示已经匹配了哪些字符
            /// </summary>
            /// <param name="skip">需要跳过的位置</param>
            /// <param name="matching">已经匹配的字符,匹配的字符用红色显示</param>
            private void PrintSeahingInfo(int skip,int matching) 
            {
                while (Console.CursorLeft > INCREMENT_3)
                {
                    Console.CursorLeft--;
                    Console.Write(' ');
                    Console.CursorLeft--;
                }
                Console.CursorLeft=Console.CursorLeft+skip*2;
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Red;
                int i;
                for (i = 0; i <matching&&i<pattern.Length; i++)
                {
                    Console.Write(pattern[i]);
                    Console.Write(' ');
                }
                Console.ForegroundColor = System.ConsoleColor.Blue;
                for (; i < pattern.Length; i++) 
                {
                    Console.Write(pattern[i]);
                    Console.Write(' ');
                }
                Console.ForegroundColor = frontColor;
                Thread.Sleep(1000);
            }
            /*
             对外提供接口,显示KMP过程
             */
            public void PerformSearching() 
            {
                KmpOverlap();
                PrintAlgorithmInfo();
                PrintTitle("Result Information:");
                PrintString("String:", seachingString);
                PrintSeahingInfo();
                int index=IndexOfKMP();
                PrintReport(index);
                Console.ReadKey();
            }
            private void PrintReport(int index)
            {
                System.ConsoleColor frontColor = Console.ForegroundColor;
                Console.ForegroundColor = System.ConsoleColor.Yellow;
                Console.CursorTop = Console.CursorTop + 1;
                Console.CursorLeft = INCREMENT_2;
                if (index < 0)
                    Console.Write("Pattern NOT found in the string !");
                else
                    Console.Write("Pattern found in the string at postion {0} !",index);
                Console.ForegroundColor = frontColor;
            }
            //实现索引,通过PrintSeahingInfo(int skip,int matching)报告最新匹配情况
            private int IndexOfKMP()
            {
                int index = -1; 
                int i, j;
                i = j = 0;
                PrintSeahingInfo(0,0);
                while (i <=seachingString.Length+j-pattern.Length)
                {
                    while (j >= 0 && seachingString[i] != pattern[j])
                    {
                        j = overlap[j];
                        if (j >=0)
                            PrintSeahingInfo(i - j, j);
                    }
                    i++;
                    j++;
                    PrintSeahingInfo(i - j, j);
                    if (j == pattern.Length)
                    {
                        index = i - pattern.Length;
                        break;
                    }
                }
                return index;
            }
        }

    代码的注释比较详细,不用解释了。ColorFullKMP提供了一个binging函数,用来接收匹配字符串和被匹配字符串。在构造函数中初始化了匹配字符串和被匹配字符串,用来直接显示KMP匹配过程。

            static void Main(string[] args)
            {
                ColorFullKMP myCoolKMP = new ColorFullKMP();
                myCoolKMP.PerformSearching();
            }
  • 相关阅读:
    说说 Java 线程间通信
    Java 内存模型与内存结构
    Spring Boot 整合 Shiro
    HashMap 实现原理
    Spring Boot 自动配置原理
    Spring Cloud 全链路追踪实现
    JVM 类加载机制
    volatile 关键字的作用
    Spring Boot 整合 Redis
    Docker命令
  • 原文地址:https://www.cnblogs.com/CaiBaoZi/p/3062847.html
Copyright © 2011-2022 走看看