[每天默写一个算法]KMP

[每天默写一个算法]KMP

作业要求:默写String的KMP算法。

KMP是经典的字符串匹配算法。复杂度为O(n+m)

 1     public static class StringKMP
 2     {
 3         /// <summary>
 4         /// This indicates that no pattern found from source.
 5         /// </summary>
 6         public const int KMPNoMatch = -1;
 7         /// <summary>
 8         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
 9         /// </summary>
10         public const int FirstBlood = -1;
11         /// <summary>
12         /// Find first match for specified pattern in the source.
13         /// </summary>
14         /// <param name="source"></param>
15         /// <param name="pattern"></param>
16         /// <returns></returns>
17         public static int KMP(this String source, String pattern)
18         {
19             if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
20             { return KMPNoMatch; }
21             var i = 0; var j = 0; var result = KMPNoMatch;
22             var nextVal = GetNextVal(pattern);
23 
24             while (i < source.Length && j < pattern.Length)
25             {
26                 if (j == FirstBlood)
27                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
28                     i++; j = 0;
29                 }
30                 else if (source[i].Equals(pattern[j]))
31                 {
32                     i++; j++;
33                 }
34                 else
35                 {// Get next j that should be compared with.
36                     j = nextVal[j];
37                 }
38             }
39 
40             if (j >= pattern.Length)// Match succeeded.
41             { result = i - pattern.Length; }
42 
43             return result;
44         }
45         /// <summary>
46         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
47         /// <para>if source[i] does NOT equal with pattern[j].</para>
48         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
49         /// <para>and j should be reset to 0.</para>
50         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
51         /// </summary>
52         /// <param name="pattern"></param>
53         /// <returns></returns>
54         private static int[] GetNextVal(String pattern)
55         {
56             var j = 0; var k = -1;
57             var nextVal = new int[pattern.Length];
58 
59             nextVal[0] = FirstBlood;
60 
61             while (j < pattern.Length - 1)
62             {
63                 if ((k == -1) || (pattern[j].Equals(pattern[k])))
64                 {
65                     j++; k++;
66                     if (!(pattern[j].Equals(pattern[k])))
67                     { nextVal[j] = k; }
68                     else
69                     { nextVal[j] = nextVal[k]; }
70                 }
71                 else
72                 { k = nextVal[k]; }
73             }
74 
75             return nextVal;
76         }
77     }

 

字符串能匹配,其他类型的串(数组Array和泛型数组IList<T>)也就可以匹配。

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 
  6 namespace System
  7 {
  8     public static class StringKMP
  9     {
 10         /// <summary>
 11         /// This indicates that no pattern found from source.
 12         /// </summary>
 13         public const int KMPNoMatch = -1;
 14         /// <summary>
 15         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
 16         /// </summary>
 17         private const int FirstBlood = -1;
 18         /// <summary>
 19         /// Find first match for specified pattern in the source.
 20         /// </summary>
 21         /// <param name="source"></param>
 22         /// <param name="pattern"></param>
 23         /// <returns></returns>
 24         public static int KMP(this String source, String pattern)
 25         {
 26             if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
 27             { return KMPNoMatch; }
 28             var i = 0; var j = 0; var result = KMPNoMatch;
 29             var nextVal = GetNextVal(pattern);
 30 
 31             while (i < source.Length && j < pattern.Length)
 32             {
 33                 if (j == FirstBlood)
 34                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
 35                     i++; j = 0;
 36                 }
 37                 else if (source[i].Equals(pattern[j]))
 38                 {
 39                     i++; j++;
 40                 }
 41                 else
 42                 {// Get next j that should be compared with.
 43                     j = nextVal[j];
 44                 }
 45             }
 46 
 47             if (j >= pattern.Length)// Match succeeded.
 48             { result = i - pattern.Length; }
 49 
 50             return result;
 51         }
 52         /// <summary>
 53         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
 54         /// <para>if source[i] does NOT equal with pattern[j].</para>
 55         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
 56         /// <para>and j should be reset to 0.</para>
 57         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
 58         /// </summary>
 59         /// <param name="pattern"></param>
 60         /// <returns></returns>
 61         private static int[] GetNextVal(String pattern)
 62         {
 63             var j = 0; var k = -1;
 64             var nextVal = new int[pattern.Length];
 65 
 66             nextVal[0] = FirstBlood;
 67 
 68             while (j < pattern.Length - 1)
 69             {
 70                 if ((k == -1) || (pattern[j].Equals(pattern[k])))
 71                 {
 72                     j++; k++;
 73                     if (!(pattern[j].Equals(pattern[k])))
 74                     { nextVal[j] = k; }
 75                     else
 76                     { nextVal[j] = nextVal[k]; }
 77                 }
 78                 else
 79                 { k = nextVal[k]; }
 80             }
 81 
 82             return nextVal;
 83         }
 84     }
 85 
 86     public static class ArrayKMP
 87     {
 88         /// <summary>
 89         /// This indicates that no pattern found from source.
 90         /// </summary>
 91         public const int KMPNoMatch = -1;
 92         /// <summary>
 93         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
 94         /// </summary>
 95         private const int FirstBlood = -1;
 96         /// <summary>
 97         /// Find first match for specified pattern in the source.
 98         /// </summary>
 99         /// <param name="source"></param>
100         /// <param name="pattern"></param>
101         /// <returns></returns>
102         public static int KMP(this Array source, Array pattern)
103         {
104             if (source == null || pattern == null || source.Length == 0 || pattern.Length == 0)
105             { return KMPNoMatch; }
106             var i = 0; var j = 0; var result = KMPNoMatch;
107             var nextVal = GetNextVal(pattern);
108 
109             while (i < source.Length && j < pattern.Length)
110             {
111                 if (j == FirstBlood)
112                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
113                     i++; j = 0;
114                 }
115                 else if (source.GetValue(i).Equals(pattern.GetValue(j)))
116                 {
117                     i++; j++;
118                 }
119                 else
120                 {// Get next j that should be compared with.
121                     j = nextVal[j];
122                 }
123             }
124 
125             if (j >= pattern.Length)// Match succeeded.
126             { result = i - pattern.Length; }
127 
128             return result;
129         }
130         /// <summary>
131         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
132         /// <para>if source[i] does NOT equal with pattern[j].</para>
133         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
134         /// <para>and j should be reset to 0.</para>
135         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
136         /// </summary>
137         /// <param name="pattern"></param>
138         /// <returns></returns>
139         private static int[] GetNextVal(Array pattern)
140         {
141             var j = 0; var k = -1;
142             var nextVal = new int[pattern.Length];
143 
144             nextVal[0] = FirstBlood;
145 
146             while (j < pattern.Length - 1)
147             {
148                 if ((k == -1) || (pattern.GetValue(j).Equals(pattern.GetValue(k))))
149                 {
150                     j++; k++;
151                     if (!(pattern.GetValue(j).Equals(pattern.GetValue(k))))
152                     { nextVal[j] = k; }
153                     else
154                     { nextVal[j] = nextVal[k]; }
155                 }
156                 else
157                 { k = nextVal[k]; }
158             }
159 
160             return nextVal;
161         }
162     }
163 
164     public static class IListKMP
165     {
166         sealed class DefaultComparer<T> : IComparer<T>
167         {
168             private static readonly DefaultComparer<T> instance = new DefaultComparer<T>();
169 
170             public static DefaultComparer<T> Instance
171             {
172                 get { return DefaultComparer<T>.instance; }
173             }
174 
175 
176             int IComparer<T>.Compare(T x, T y)
177             {
178                 if (x.Equals(y)) { return 0; }
179                 else { return 1; }
180             }
181         }
182 
183         /// <summary>
184         /// This indicates that no pattern found from source.
185         /// </summary>
186         public const int KMPNoMatch = -1;
187         /// <summary>
188         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
189         /// </summary>
190         private const int FirstBlood = -1;
191         /// <summary>
192         /// Find first match for specified pattern in the source.
193         /// </summary>
194         /// <param name="source"></param>
195         /// <param name="pattern"></param>
196         /// <param name="comparer"></param>
197         /// <returns></returns>
198         public static int KMP<T>(this IList<T> source, IList<T> pattern, IComparer<T> comparer = null)
199         {
200             if (source == null || pattern == null || source.Count == 0 || pattern.Count == 0)
201             { return KMPNoMatch; }
202 
203             if (comparer == null) { comparer = DefaultComparer<T>.Instance; }
204 
205             var i = 0; var j = 0; var result = KMPNoMatch;
206             var nextVal = GetNextVal(pattern, comparer);
207 
208             while (i < source.Count && j < pattern.Count)
209             {
210                 if (j == FirstBlood)
211                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
212                     i++; j = 0;
213                 }
214                 else if (comparer.Compare(source[i], pattern[j]) == 0) //(source[i].Equals(pattern[j]))
215                 {
216                     i++; j++;
217                 }
218                 else
219                 {// Get next j that should be compared with.
220                     j = nextVal[j];
221                 }
222             }
223 
224             if (j >= pattern.Count)// Match succeeded.
225             { result = i - pattern.Count; }
226 
227             return result;
228         }
229 
230         /// <summary>
231         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
232         /// <para>if source[i] does NOT equal with pattern[j].</para>
233         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
234         /// <para>and j should be reset to 0.</para>
235         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
236         /// </summary>
237         /// <param name="pattern"></param>
238         /// <returns></returns>
239         private static int[] GetNextVal<T>(IList<T> pattern, IComparer<T> comparer)
240         {
241             var j = 0; var k = -1;
242             var nextVal = new int[pattern.Count];
243 
244             nextVal[0] = FirstBlood;
245 
246             while (j < pattern.Count - 1)
247             {
248                 if ((k == -1) || (comparer.Compare(pattern[j], pattern[k]) == 0))
249                 {
250                     j++; k++;
251                     if (!(comparer.Compare(pattern[j], pattern[k]) == 0))
252                     { nextVal[j] = k; }
253                     else
254                     { nextVal[j] = nextVal[k]; }
255                 }
256                 else
257                 { k = nextVal[k]; }
258             }
259 
260             return nextVal;
261         }
262 
263     }
264 
265 }

 


 
 

 

 

posted @ 2014-02-26 15:23  BIT祝威  阅读(1678)  评论(0编辑  收藏  举报
canvas start.

canvas end.