victory 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +11 -1
  4. data/README.md +4 -6
  5. data/Rakefile +11 -4
  6. data/USAGE.md +159 -0
  7. data/ext/algorithms/string/LICENSE.md +21 -0
  8. data/ext/algorithms/string/extconf.rb +4 -0
  9. data/ext/algorithms/string/string.c +68 -0
  10. data/ext/containers/bst/LICENSE.md +21 -0
  11. data/ext/containers/bst/bst.c +247 -0
  12. data/ext/containers/bst/extconf.rb +4 -0
  13. data/ext/containers/deque/LICENSE.md +21 -0
  14. data/ext/containers/deque/deque.c +247 -0
  15. data/ext/containers/deque/extconf.rb +4 -0
  16. data/ext/containers/rbtree_map/LICENSE.md +21 -0
  17. data/ext/containers/rbtree_map/extconf.rb +4 -0
  18. data/ext/containers/rbtree_map/rbtree.c +498 -0
  19. data/ext/containers/splaytree_map/LICENSE.md +21 -0
  20. data/ext/containers/splaytree_map/extconf.rb +4 -0
  21. data/ext/containers/splaytree_map/splaytree.c +419 -0
  22. data/ext/containers/xor_list/extconf.rb +4 -0
  23. data/ext/containers/xor_list/xor_list.c +122 -0
  24. data/lib/algorithms/search.rb +104 -0
  25. data/lib/algorithms/sort.rb +389 -0
  26. data/lib/algorithms/string.rb +29 -0
  27. data/lib/containers/deque.rb +193 -0
  28. data/lib/containers/heap.rb +524 -0
  29. data/lib/containers/kd_tree.rb +131 -0
  30. data/lib/containers/list.rb +81 -0
  31. data/lib/containers/prefix_tree.rb +61 -0
  32. data/lib/containers/priority_queue.rb +135 -0
  33. data/lib/containers/queue.rb +89 -0
  34. data/lib/containers/rb_tree_map.rb +420 -0
  35. data/lib/containers/splay_tree_map.rb +290 -0
  36. data/lib/containers/stack.rb +88 -0
  37. data/lib/containers/suffix_array.rb +92 -0
  38. data/lib/containers/trie.rb +204 -0
  39. data/lib/containers/tuple.rb +20 -0
  40. data/lib/victory/version.rb +1 -1
  41. data/lib/victory.rb +8 -1
  42. data/victory.gemspec +12 -3
  43. metadata +73 -12
  44. data/.idea/encodings.xml +0 -4
  45. data/.idea/misc.xml +0 -7
  46. data/.idea/modules.xml +0 -8
  47. data/.idea/victory.iml +0 -13
  48. data/.idea/workspace.xml +0 -233
  49. data/ext/victory/extconf.rb +0 -3
  50. data/ext/victory/victory.c +0 -9
  51. data/ext/victory/victory.h +0 -6
@@ -0,0 +1,419 @@
1
+ #include "ruby.h"
2
+
3
+ #define node_size(x) (((x)==NULL) ? 0 : ((x)->size))
4
+
5
+ /* Using http://www.link.cs.cmu.edu/link/ftp-site/splaying/top-down-size-splay.c as reference,
6
+ written by D. Sleator <sleator@cs.cmu.edu>, January 1994.
7
+ */
8
+
9
+ typedef struct struct_splaytree_node {
10
+ VALUE key;
11
+ VALUE value;
12
+ int size;
13
+ struct struct_splaytree_node *left;
14
+ struct struct_splaytree_node *right;
15
+ } splaytree_node;
16
+
17
+ typedef struct {
18
+ int (*compare_function)(VALUE key1, VALUE key2);
19
+ splaytree_node *root;
20
+ } splaytree;
21
+
22
+ typedef struct struct_ll_node {
23
+ splaytree_node *node;
24
+ struct struct_ll_node *next;
25
+ } ll_node;
26
+
27
+ static void recursively_free_nodes(splaytree_node *node) {
28
+ if(node) {
29
+ recursively_free_nodes(node->left);
30
+ recursively_free_nodes(node->right);
31
+ xfree(node);
32
+ }
33
+ return;
34
+ }
35
+
36
+ static splaytree* get_tree_from_self(VALUE self) {
37
+ splaytree *tree;
38
+ Data_Get_Struct(self, splaytree, tree);
39
+ return tree;
40
+ }
41
+
42
+ static splaytree_node* splay(splaytree *tree, splaytree_node *n, VALUE key) {
43
+ int cmp, cmp2, root_size, l_size, r_size;
44
+ splaytree_node N;
45
+ splaytree_node *l, *r, *y;
46
+
47
+ if (!n) return n;
48
+
49
+ N.left = N.right = NULL;
50
+ l = r = &N;
51
+ root_size = node_size(n);
52
+ l_size = r_size = 0;
53
+
54
+ while(1) {
55
+ cmp = tree->compare_function(key, n->key);
56
+ if (cmp == -1) {
57
+ if (!n->left) break;
58
+ cmp2 = tree->compare_function(key, n->left->key);
59
+ if (cmp2 == -1) {
60
+ y = n->left;
61
+ n->left = y->right;
62
+ y->right = n;
63
+ n->size = node_size(n->left) + node_size(n->right) + 1;
64
+ n = y;
65
+ if (!n->left) break;
66
+ }
67
+ r->left = n;
68
+ r = n;
69
+ n = n->left;
70
+ r_size += 1 + node_size(r->right);
71
+ } else if (cmp == 1) {
72
+ if (!n->right) break;
73
+ cmp2 = tree->compare_function(key, n->right->key);
74
+ if (cmp2 == 1) {
75
+ y = n->right;
76
+ n->right = y->left;
77
+ y->left = n;
78
+ n->size = node_size(n->left) + node_size(n->right) + 1;
79
+ n = y;
80
+ if (!n->right) break;
81
+ }
82
+ l->right = n;
83
+ l = n;
84
+ n = n->right;
85
+ l_size += 1 + node_size(l->left);
86
+ } else {
87
+ break;
88
+ }
89
+ }
90
+
91
+ l_size += node_size(n->left);
92
+ r_size += node_size(n->right);
93
+ n->size = l_size + r_size + 1;
94
+ l->right = r->left = NULL;
95
+
96
+ for (y = N.right; y != NULL; y = y->right) {
97
+ y->size = l_size;
98
+ l_size -= 1 + node_size(y->left);
99
+ }
100
+ for (y = N.left; y != NULL; y = y->left) {
101
+ y->size = r_size;
102
+ r_size -= 1 + node_size(y->right);
103
+ }
104
+
105
+ l->right = n->left;
106
+ r->left = n->right;
107
+ n->left = N.right;
108
+ n->right = N.left;
109
+
110
+ return n;
111
+ }
112
+
113
+ static int height(splaytree_node *h) {
114
+ int left_height, right_height;
115
+
116
+ if(!h) { return 0; }
117
+
118
+ left_height = 1 + height(h->left);
119
+ right_height = 1 + height(h->right);
120
+
121
+ return left_height > right_height ? left_height : right_height;
122
+ }
123
+
124
+ static splaytree* create_splaytree(int (*compare_function)(VALUE, VALUE)) {
125
+ splaytree *tree = ALLOC(splaytree);
126
+ tree->compare_function = compare_function;
127
+ tree->root = NULL;
128
+ return tree;
129
+ }
130
+
131
+ static splaytree_node* create_node(VALUE key, VALUE value) {
132
+ splaytree_node *new_node = ALLOC(splaytree_node);
133
+ new_node->key = key;
134
+ new_node->value = value;
135
+ new_node->left = NULL;
136
+ new_node->right = NULL;
137
+ return new_node;
138
+ }
139
+
140
+ static splaytree_node* insert(splaytree *tree, splaytree_node *n, VALUE key, VALUE value) {
141
+ int cmp;
142
+ splaytree_node *new_node;
143
+
144
+ if (n) {
145
+ n = splay(tree, n, key);
146
+ cmp = tree->compare_function(key, n->key);
147
+ if (cmp == 0) {
148
+ n->value = value;
149
+ return n;
150
+ }
151
+ }
152
+ new_node = create_node(key, value);
153
+ if (!n) {
154
+ new_node->left = new_node->right = NULL;
155
+ } else {
156
+ cmp = tree->compare_function(key, n->key);
157
+ if (cmp < 0) {
158
+ new_node->left = n->left;
159
+ new_node->right = n;
160
+ n->left = NULL;
161
+ n->size = 1 + node_size(n->right);
162
+ } else {
163
+ new_node->right = n->right;
164
+ new_node->left = n;
165
+ n->right = NULL;
166
+ n->size = 1 + node_size(n->left);
167
+ }
168
+ }
169
+ new_node->size = 1 + node_size(new_node->left) + node_size(new_node->right);
170
+ return new_node;
171
+ }
172
+
173
+ static VALUE get(splaytree *tree, VALUE key) {
174
+ int cmp;
175
+
176
+ if (!tree->root)
177
+ return Qnil;
178
+
179
+ tree->root = splay(tree, tree->root, key);
180
+ cmp = tree->compare_function(key, tree->root->key);
181
+ if (cmp == 0) {
182
+ return tree->root->value;
183
+ }
184
+ return Qnil;
185
+ }
186
+
187
+ static splaytree_node* delete(splaytree *tree, splaytree_node *n, VALUE key, VALUE *deleted) {
188
+ int cmp, tsize;
189
+ splaytree_node *x;
190
+
191
+ tsize = n->size;
192
+ n = splay(tree, n, key);
193
+ cmp = tree->compare_function(key, n->key);
194
+ if (cmp == 0) {
195
+ *deleted = n->value;
196
+ if (!n->left) {
197
+ x = n->right;
198
+ } else {
199
+ x = splay(tree, n->left, key);
200
+ x->right = n->right;
201
+ }
202
+ xfree(n);
203
+ if (x) {
204
+ x->size = tsize-1;
205
+ }
206
+ return x;
207
+ }
208
+ return n;
209
+ }
210
+
211
+ static splaytree* splaytree_each_node(splaytree *tree, splaytree_node *node, void (*each)(splaytree *tree_, splaytree_node *node_, void* args), void* arguments) {
212
+ if (!node)
213
+ return NULL;
214
+
215
+ if (node->left)
216
+ splaytree_each_node(tree, node->left, each, arguments);
217
+
218
+ (*each)(tree, node, arguments);
219
+
220
+ if (node->right)
221
+ splaytree_each_node(tree, node->right, each, arguments);
222
+ return tree;
223
+ }
224
+
225
+ static splaytree* splay_each(splaytree *tree, void (*each)(splaytree *tree, splaytree_node *node, void *args), void* arguments) {
226
+ if (tree->root)
227
+ splaytree_each_node(tree, tree->root, each, arguments);
228
+ return tree;
229
+ }
230
+
231
+ // Methods to be called in Ruby
232
+
233
+ static VALUE id_compare_operator;
234
+
235
+ static int splaytree_compare_function(VALUE a, VALUE b) {
236
+ if (a == b) return 0;
237
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
238
+ long x = FIX2LONG(a), y = FIX2LONG(b);
239
+ if (x == y) return 0;
240
+ if (x > y) return 1;
241
+ return -1;
242
+ }
243
+ if (TYPE(a) == T_STRING && rb_obj_is_kind_of(a, rb_cString) &&
244
+ TYPE(b) == T_STRING && rb_obj_is_kind_of(b, rb_cString)) {
245
+ return rb_str_cmp(a, b);
246
+ }
247
+ return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
248
+ }
249
+
250
+ static VALUE splaytree_init(VALUE self)
251
+ {
252
+ return self;
253
+ }
254
+
255
+ static void splaytree_mark(void *ptr) {
256
+ ll_node *current, *new, *last, *old;
257
+ if (ptr) {
258
+ splaytree *tree = ptr;
259
+
260
+ if (tree->root) {
261
+ current = ALLOC(ll_node);
262
+ last = current;
263
+ current->node = tree->root;
264
+ current->next = NULL;
265
+
266
+ while(current) {
267
+ rb_gc_mark(current->node->key);
268
+ rb_gc_mark(current->node->value);
269
+ if (current->node->left) {
270
+ new = ALLOC(ll_node);
271
+ new->node = current->node->left;
272
+ new->next = NULL;
273
+ last->next = new;
274
+ last = new;
275
+ }
276
+ if (current->node->right) {
277
+ new = ALLOC(ll_node);
278
+ new->node = current->node->right;
279
+ new->next = NULL;
280
+ last->next = new;
281
+ last = new;
282
+ }
283
+ old = current;
284
+ current = current->next;
285
+ xfree(old);
286
+ }
287
+ }
288
+ }
289
+ }
290
+
291
+ static void splaytree_free(void *ptr) {
292
+ if (ptr) {
293
+ splaytree *tree = ptr;
294
+ recursively_free_nodes(tree->root);
295
+ xfree(tree);
296
+ }
297
+ }
298
+
299
+ static VALUE splaytree_alloc(VALUE klass) {
300
+ splaytree *tree = create_splaytree(&splaytree_compare_function);
301
+ return Data_Wrap_Struct(klass, splaytree_mark, splaytree_free, tree);
302
+ }
303
+
304
+ static VALUE splaytree_push(VALUE self, VALUE key, VALUE value) {
305
+ splaytree *tree = get_tree_from_self(self);
306
+ tree->root = insert(tree, tree->root, key, value);
307
+ return value;
308
+ }
309
+
310
+ static VALUE splaytree_get(VALUE self, VALUE key) {
311
+ splaytree *tree = get_tree_from_self(self);
312
+ return get(tree, key);
313
+ }
314
+
315
+ static VALUE splaytree_size(VALUE self) {
316
+ splaytree *tree = get_tree_from_self(self);
317
+ if(!tree->root) { return INT2NUM(0); }
318
+ return INT2NUM(tree->root->size);
319
+ }
320
+
321
+ static VALUE splaytree_is_empty(VALUE self) {
322
+ splaytree *tree = get_tree_from_self(self);
323
+ return (tree->root ? Qfalse : Qtrue);
324
+ }
325
+
326
+ static VALUE splaytree_height(VALUE self) {
327
+ splaytree *tree = get_tree_from_self(self);
328
+ return INT2NUM(height(tree->root));
329
+ }
330
+
331
+ static VALUE splaytree_has_key(VALUE self, VALUE key) {
332
+ splaytree *tree = get_tree_from_self(self);
333
+ if(!tree->root) { return Qfalse; }
334
+ if(get(tree, key) == Qnil)
335
+ return Qfalse;
336
+
337
+ return Qtrue;
338
+ }
339
+
340
+ static VALUE splaytree_min_key(VALUE self) {
341
+ splaytree *tree = get_tree_from_self(self);
342
+ splaytree_node *node;
343
+
344
+ if(!tree->root)
345
+ return Qnil;
346
+
347
+ node = tree->root;
348
+ while (node->left)
349
+ node = node->left;
350
+
351
+ return node->key;
352
+ }
353
+
354
+ static VALUE splaytree_max_key(VALUE self) {
355
+ splaytree *tree = get_tree_from_self(self);
356
+ splaytree_node *node;
357
+
358
+ if(!tree->root)
359
+ return Qnil;
360
+
361
+ node = tree->root;
362
+ while (node->right)
363
+ node = node->right;
364
+
365
+ return node->key;
366
+ }
367
+
368
+ static VALUE splaytree_delete(VALUE self, VALUE key) {
369
+ VALUE deleted = Qnil;
370
+ splaytree *tree = get_tree_from_self(self);
371
+ if(!tree->root)
372
+ return Qnil;
373
+
374
+ tree->root = delete(tree, tree->root, key, &deleted);
375
+ return deleted;
376
+ }
377
+
378
+ static VALUE splaytree_clear(VALUE self) {
379
+ splaytree *tree = get_tree_from_self(self);
380
+ recursively_free_nodes(tree->root);
381
+ tree->root = NULL;
382
+ return Qnil;
383
+ }
384
+
385
+ static void splaytree_each_helper(splaytree *tree, splaytree_node *node, void *args) {
386
+ rb_yield(rb_ary_new3(2, node->key, node->value));
387
+ };
388
+
389
+ static VALUE splaytree_each(VALUE self) {
390
+ splaytree *tree = get_tree_from_self(self);
391
+ splay_each(tree, &splaytree_each_helper, NULL);
392
+ return self;
393
+ }
394
+
395
+ static VALUE CSplayTree;
396
+ static VALUE mContainers;
397
+
398
+ void Init_CSplayTreeMap() {
399
+ id_compare_operator = rb_intern("<=>");
400
+
401
+ mContainers = rb_define_module("Containers");
402
+ CSplayTree = rb_define_class_under(mContainers, "CSplayTreeMap", rb_cObject);
403
+ rb_define_alloc_func(CSplayTree, splaytree_alloc);
404
+ rb_define_method(CSplayTree, "initialize", splaytree_init, 0);
405
+ rb_define_method(CSplayTree, "push", splaytree_push, 2);
406
+ rb_define_method(CSplayTree, "clear", splaytree_clear, 0);
407
+ rb_define_alias(CSplayTree, "[]=", "push");
408
+ rb_define_method(CSplayTree, "size", splaytree_size, 0);
409
+ rb_define_method(CSplayTree, "empty?", splaytree_is_empty, 0);
410
+ rb_define_method(CSplayTree, "height", splaytree_height, 0);
411
+ rb_define_method(CSplayTree, "min_key", splaytree_min_key, 0);
412
+ rb_define_method(CSplayTree, "max_key", splaytree_max_key, 0);
413
+ rb_define_method(CSplayTree, "each", splaytree_each, 0);
414
+ rb_define_method(CSplayTree, "get", splaytree_get, 1);
415
+ rb_define_alias(CSplayTree, "[]", "get");
416
+ rb_define_method(CSplayTree, "has_key?", splaytree_has_key, 1);
417
+ rb_define_method(CSplayTree, "delete", splaytree_delete, 1);
418
+ rb_include_module(CSplayTree, rb_eval_string("Enumerable"));
419
+ }
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ extension_name = "XORList"
3
+ dir_config(extension_name)
4
+ create_makefile(extension_name)
@@ -0,0 +1,122 @@
1
+ #include "ruby.h"
2
+
3
+ typedef struct struct_node {
4
+ VALUE obj;
5
+ struct struct_node *npx; // XOR of next and previous
6
+ } node;
7
+
8
+ typedef struct {
9
+ unsigned int size;
10
+ node *front;
11
+ node *back;
12
+ } xor_list;
13
+
14
+ node* xor(node *a, node *b)
15
+ {
16
+ return (node*) ((uintptr_t) (a) ^ (uintptr_t) (b));
17
+ }
18
+
19
+ static xor_list* get_xor_list(VALUE self) {
20
+ xor_list *list;
21
+ Data_Get_Struct(self, xor_list, list);
22
+ return list;
23
+ }
24
+
25
+ static xor_list* create_xor_list() {
26
+ xor_list *list = ALLOC(xor_list);
27
+ list->size = 0;
28
+ list->front = NULL;
29
+ list->back = NULL;
30
+ return list;
31
+ }
32
+
33
+ static void xor_list_mark(void *ptr) {
34
+ node *prev = NULL, *next = NULL;
35
+ if (ptr) {
36
+ xor_list *list = ptr;
37
+ node *current = list->front;
38
+ while(current) {
39
+ rb_gc_mark(current->obj);
40
+ next = xor(prev, current->npx);
41
+ prev = current;
42
+ current = next;
43
+ }
44
+ }
45
+ }
46
+
47
+ void free_nodes(node *current) {
48
+ node *prev = NULL, *next = NULL;
49
+ while(current) {
50
+ xfree(current);
51
+ next = xor(prev, current->npx);
52
+ prev = current;
53
+ current = next;
54
+ }
55
+ return;
56
+ }
57
+
58
+ static void xor_list_free(void *ptr) {
59
+ if (ptr) {
60
+ xor_list *list = ptr;
61
+ free_nodes(list->front);
62
+ xfree(list);
63
+ }
64
+ }
65
+
66
+ static VALUE xor_list_alloc(VALUE klass) {
67
+ xor_list *list = create_xor_list();
68
+ return Data_Wrap_Struct(klass, xor_list_mark, xor_list_free, list);
69
+ }
70
+
71
+ static node* create_node(VALUE obj) {
72
+ node *n = ALLOC(node);
73
+ n->obj = obj;
74
+ n->npx = NULL;
75
+ return n;
76
+ }
77
+
78
+ static VALUE xor_list_init(VALUE self)
79
+ {
80
+ return self;
81
+ }
82
+
83
+ static VALUE xor_list_push_front(VALUE self, VALUE obj) {
84
+ xor_list *list = get_xor_list(self);
85
+ node *current = create_node(obj);
86
+ if(list->front) {
87
+ current->npx = xor(NULL, list->front);
88
+ list->front->npx = xor(current, xor(NULL, list->front->npx));
89
+ }
90
+ else {
91
+ list->back = current;
92
+ }
93
+ list->front = current;
94
+ list->size++;
95
+ return obj;
96
+ }
97
+
98
+ static VALUE xor_list_each(VALUE self) {
99
+ xor_list *list = get_xor_list(self);
100
+ node *current = list->front;
101
+ node *prev = NULL, *next = NULL;
102
+ while(current) {
103
+ rb_yield(current->obj);
104
+ next = xor(prev, current->npx);
105
+ prev = current;
106
+ current = next;
107
+ }
108
+ return self;
109
+ }
110
+
111
+ static VALUE list;
112
+ static VALUE containers;
113
+
114
+ void Init_XORList() {
115
+ containers = rb_define_module("Containers");
116
+ list = rb_define_class_under(containers, "XORList", rb_cObject);
117
+ rb_define_alloc_func(list, xor_list_alloc);
118
+ rb_define_method(list, "initialize", xor_list_init, 0);
119
+ rb_define_method(list, "push_front", xor_list_push_front, 1);
120
+ rb_define_method(list, "each", xor_list_each, 0);
121
+ rb_include_module(list, rb_eval_string("Enumerable"));
122
+ }
@@ -0,0 +1,104 @@
1
+ # rdoc
2
+ # This module implements search algorithms. Documentation is provided for each algorithm.
3
+ #
4
+ # MIT License
5
+ #
6
+ # Copyright (c) 2009 Kanwei Li
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ # of this software and associated documentation files (the "Software"), to deal
10
+ # in the Software without restriction, including without limitation the rights
11
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ # copies of the Software, and to permit persons to whom the Software is
13
+ # furnished to do so, subject to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be included in all
16
+ # copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ # SOFTWARE.
25
+ module Algorithms::Search
26
+ # Binary Search: This search finds an item in log(n) time provided that the container is already sorted.
27
+ # The method returns the item if it is found, or nil if it is not. If there are duplicates, the first one
28
+ # found is returned, and this is not guaranteed to be the smallest or largest item.
29
+ #
30
+ # Complexity: O(lg N)
31
+ #
32
+ # Algorithms::Search.binary_search([1, 2, 3], 1) #=> 1
33
+ # Algorithms::Search.binary_search([1, 2, 3], 4) #=> nil
34
+ def self.binary_search(container, item)
35
+ return nil if item.nil?
36
+ low = 0
37
+ high = container.size - 1
38
+ while low <= high
39
+ mid = (low + high) / 2
40
+ val = container[mid]
41
+ if val > item
42
+ high = mid - 1
43
+ elsif val < item
44
+ low = mid + 1
45
+ else
46
+ return val
47
+ end
48
+ end
49
+ nil
50
+ end
51
+
52
+ # Knuth-Morris-Pratt Algorithm substring search algorithm: Efficiently finds the starting position of a
53
+ # substring in a string. The algorithm calculates the best position to resume searching from if a failure
54
+ # occurs.
55
+ #
56
+ # The method returns the index of the starting position in the string where the substring is found. If there
57
+ # is no match, nil is returned.
58
+ #
59
+ # Complexity: O(n + k), where n is the length of the string and k is the length of the substring.
60
+ #
61
+ # Algorithms::Search.kmp_search("ABC ABCDAB ABCDABCDABDE", "ABCDABD") #=> 15
62
+ # Algorithms::Search.kmp_search("ABC ABCDAB ABCDABCDABDE", "ABCDEF") #=> nil
63
+ def self.kmp_search(string, substring)
64
+ return nil if string.nil? or substring.nil?
65
+
66
+ # create failure function table
67
+ pos = 2
68
+ cnd = 0
69
+ failure_table = [-1, 0]
70
+ while pos < substring.length
71
+ if substring[pos - 1] == substring[cnd]
72
+ failure_table[pos] = cnd + 1
73
+ pos += 1
74
+ cnd += 1
75
+ elsif cnd > 0
76
+ cnd = failure_table[cnd]
77
+ else
78
+ failure_table[pos] = 0
79
+ pos += 1
80
+ end
81
+ end
82
+
83
+ m = i = 0
84
+ while m + i < string.length
85
+ if substring[i] == string[m + i]
86
+ i += 1
87
+ return m if i == substring.length
88
+ else
89
+ m = m + i - failure_table[i]
90
+ i = failure_table[i] if i > 0
91
+ end
92
+ end
93
+ return nil
94
+ end
95
+
96
+ # Allows kmp_search to be called as an instance method in classes that include the Search module.
97
+ #
98
+ # class String; include Algorithms::Search; end
99
+ # "ABC ABCDAB ABCDABCDABDE".kmp_search("ABCDABD") #=> 15
100
+ def kmp_search(substring)
101
+ Algorithms::Search.kmp_search(self, substring)
102
+ end
103
+
104
+ end