Boyer-Moore (C#)

99封情书 提交于 2020-04-08 12:28:50

调用ShowExample方法即可查看结果

使用Debug配置编译可以查看详细匹配过程

using System;
using System.Collections.Generic;

namespace Algorithms
{
    /// <summary>
    /// An implemention of Boyer-Moore algorithm.
    /// <para/>author : Ornithopter
    /// </summary>
    class BoyerMooreSearch
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="pattern"></param>
        /// <returns>An array of matched index</returns>
        public int[] Search(string source, string pattern)
        {
            var matchIndexes = new List<int>();

            // step increasment.
            var delta = 0;

            // prepare a map providing delta for each char in pattern string.
            var deltaMap = CreateDeltaMap(pattern);

            // for display.
            var indent = pattern.Length;
            DebugUtil.WriteLine(source);

            // start searching.
            for (int i = pattern.Length - 1; i < source.Length; i += delta)
            {
                // for display.
                indent += delta;
                DebugUtil.Write(String.Format("{0}({1})", pattern.PadLeft(indent, '.'), delta));

                // find next match and update delta.
                if (FindNext(source, pattern, i, deltaMap, out delta))
                {
                    // add to result list if found.
                    matchIndexes.Add(i - (pattern.Length - 1));

                    DebugUtil.Write("√");
                }

                // new line.
                DebugUtil.WriteLine();
            }
            return matchIndexes.ToArray();
        }

        /// <summary>
        /// Find the next matched index and update delte at the same time.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="pattern"></param>
        /// <param name="start"></param>
        /// <param name="deltaMap"></param>
        /// <param name="delta"></param>
        /// <returns>true if found one, otherwise false.</returns>
        private bool FindNext(string source, string pattern, int start, int[] deltaMap, out int delta)
        {
            int i = pattern.Length - 1,
                index = 0;

            // start comparing from the last char in pattern.
            while (source[start - index] == pattern[i - index])
            {
                if (index != pattern.Length - 1)
                {
                    index++;
                }
                else
                {
                    // matchs to the end. So it's a search result.
                    delta = pattern.Length;
                    return true;
                }
            }

            // found one dismatched char at (start - index), get delta from map.
            var c = source[start - index];
            delta = deltaMap[c];

            if (delta <= index)
            {
                // this means the source[start] char is the last char in pattern
                // and only appears once. So delta should be the length of pattern.
                delta = pattern.Length;
            }
            else
            {
                delta = delta - index;
            }
            return false;
        }

        int[] CreateDeltaMap(string pattern)
        {
            const int AlphabetSize = 128;
            int patternLength = pattern.Length;
            var deltaMap = new int[AlphabetSize];

            // initialize the map.
            for (int i = 0; i < AlphabetSize; i++)
            {
                deltaMap[i] = patternLength;
            }

            // start from 0, which means any duplicated char will only have
            // the index nearest to the end.
            for (int i = 0; i < patternLength; i++)
            {
                deltaMap[pattern[i]] = patternLength - i - 1;
            }
            return deltaMap;
        }

        public void ShowExample()
        {
            // source string and pattern string are in one string and splited by ','.
            var examples = new[] 
            {
                "a b,b",
                "AAAABAA,BA",
                "awataa,wat",
                "here is a simple example,ample",
                "here is a simple example,example",
                "AAAABAAAABAAABAAA,AB",
                "awaaaaaaaawrwatawt,awrwatawt",
            };
            foreach (var example in examples)
            {
                var source = example.Split(',')[0];
                var pattern = example.Split(',')[1];
                var result = Search(source, pattern);
                DebugUtil.WriteLine("{0} <-> {1} : {2}", source, pattern, String.Join(",", result));
            }

        }
    }
}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!