algorithms-aunderwo 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +9 -0
  2. data/History.txt +176 -0
  3. data/Manifest +47 -0
  4. data/README.markdown +93 -0
  5. data/Rakefile +31 -0
  6. data/VERSION +1 -0
  7. data/algorithms-aunderwo.gemspec +110 -0
  8. data/algorithms.gemspec +32 -0
  9. data/benchmarks/deque.rb +17 -0
  10. data/benchmarks/sorts.rb +34 -0
  11. data/benchmarks/treemaps.rb +51 -0
  12. data/ext/algorithms/string/extconf.rb +4 -0
  13. data/ext/algorithms/string/string.c +68 -0
  14. data/ext/containers/bst/bst.c +247 -0
  15. data/ext/containers/bst/extconf.rb +4 -0
  16. data/ext/containers/deque/deque.c +247 -0
  17. data/ext/containers/deque/extconf.rb +4 -0
  18. data/ext/containers/rbtree_map/extconf.rb +4 -0
  19. data/ext/containers/rbtree_map/rbtree.c +498 -0
  20. data/ext/containers/splaytree_map/extconf.rb +4 -0
  21. data/ext/containers/splaytree_map/splaytree.c +419 -0
  22. data/lib/algorithms.rb +65 -0
  23. data/lib/algorithms/search.rb +84 -0
  24. data/lib/algorithms/sort.rb +238 -0
  25. data/lib/algorithms/string.rb +8 -0
  26. data/lib/containers/deque.rb +171 -0
  27. data/lib/containers/heap.rb +486 -0
  28. data/lib/containers/kd_tree.rb +110 -0
  29. data/lib/containers/priority_queue.rb +113 -0
  30. data/lib/containers/queue.rb +68 -0
  31. data/lib/containers/rb_tree_map.rb +398 -0
  32. data/lib/containers/splay_tree_map.rb +269 -0
  33. data/lib/containers/stack.rb +67 -0
  34. data/lib/containers/suffix_array.rb +68 -0
  35. data/lib/containers/trie.rb +182 -0
  36. data/spec/bst_gc_mark_spec.rb +25 -0
  37. data/spec/bst_spec.rb +25 -0
  38. data/spec/deque_gc_mark_spec.rb +18 -0
  39. data/spec/deque_spec.rb +108 -0
  40. data/spec/heap_spec.rb +126 -0
  41. data/spec/kd_expected_out.txt +10000 -0
  42. data/spec/kd_test_in.txt +10000 -0
  43. data/spec/kd_tree_spec.rb +34 -0
  44. data/spec/map_gc_mark_spec.rb +27 -0
  45. data/spec/priority_queue_spec.rb +75 -0
  46. data/spec/queue_spec.rb +61 -0
  47. data/spec/rb_tree_map_spec.rb +123 -0
  48. data/spec/search_spec.rb +28 -0
  49. data/spec/sort_spec.rb +28 -0
  50. data/spec/splay_tree_map_spec.rb +106 -0
  51. data/spec/stack_spec.rb +60 -0
  52. data/spec/string_spec.rb +13 -0
  53. data/spec/suffix_array_spec.rb +40 -0
  54. data/spec/trie_spec.rb +59 -0
  55. metadata +138 -0
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{algorithms}
5
+ s.version = "0.2.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Kanwei Li"]
9
+ s.date = %q{2009-03-29}
10
+ s.description = %q{A library of algorithms and containers.}
11
+ s.email = %q{kanwei@gmail.com}
12
+ s.extensions = ["ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/splaytree_map/extconf.rb"]
13
+ s.extra_rdoc_files = ["ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "README.markdown"]
14
+ s.files = ["algorithms.gemspec", "benchmarks/deque.rb", "benchmarks/sorts.rb", "benchmarks/treemaps.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "History.txt", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "Manifest", "Rakefile", "README.markdown", "spec/deque_gc_mark_spec.rb", "spec/deque_spec.rb", "spec/heap_spec.rb", "spec/kd_tree_spec.rb", "spec/priority_queue_spec.rb", "spec/queue_spec.rb", "spec/rb_tree_map_gc_mark_spec.rb", "spec/rb_tree_map_spec.rb", "spec/search_spec.rb", "spec/sort_spec.rb", "spec/splay_tree_map_spec.rb", "spec/stack_spec.rb", "spec/suffix_array_spec.rb", "spec/trie_spec.rb"]
15
+ s.has_rdoc = true
16
+ s.homepage = %q{http://rubyforge.org/projects/algorithms/}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Algorithms", "--main", "README.markdown"]
18
+ s.require_paths = ["lib", "ext"]
19
+ s.rubyforge_project = %q{algorithms}
20
+ s.rubygems_version = %q{1.3.1}
21
+ s.summary = %q{A library of algorithms and containers.}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ require 'rubygems'
6
+ require 'rbench'
7
+
8
+ RBench.run(2) do
9
+ %w(array deque).each { |s| self.send(:column, s.intern) }
10
+ deque = Containers::Deque.new
11
+ array = []
12
+
13
+ report "Insertion at end" do
14
+ array { 1000000.times { |x| array << x } }
15
+ deque { 1000000.times { |x| deque.push_back(x) } }
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ require 'rubygems'
6
+ require 'rbench'
7
+
8
+ RBench.run(5) do
9
+
10
+ sorts = %w(ruby comb_sort heapsort insertion_sort shell_sort quicksort mergesort)
11
+ sorts.each { |sort| self.send(:column, sort.intern) }
12
+
13
+ n = 1000
14
+
15
+ proc = lambda { |scope, ary|
16
+ scope.ruby { ary.dup.sort }
17
+ scope.comb_sort { Sort.comb_sort(ary.dup) }
18
+ scope.heapsort { Sort.heapsort(ary.dup) }
19
+ scope.insertion_sort { Sort.insertion_sort(ary.dup) }
20
+ scope.shell_sort { Sort.shell_sort(ary.dup) }
21
+ scope.quicksort { Sort.quicksort(ary.dup) }
22
+ scope.mergesort { Sort.mergesort(ary.dup) }
23
+ }
24
+
25
+ report "Already sorted" do
26
+ sorted_array = Array.new(n) { rand(n) }.sort
27
+ proc.call(self, sorted_array)
28
+ end
29
+
30
+ report "Random" do
31
+ random_array = Array.new(n) { rand(n) }
32
+ proc.call(self, random_array)
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Containers
4
+
5
+ require 'rubygems'
6
+ require 'rbench'
7
+
8
+ RBench.run(2) do
9
+ trees = %w(hash rbtree splaytree)
10
+ trees.each { |tree| self.send(:column, tree.intern) }
11
+
12
+ rbtree = RBTreeMap.new
13
+ splaytree = SplayTreeMap.new
14
+ hash = Hash.new
15
+
16
+ random_array = Array.new(300000) { |i| rand(i) }
17
+
18
+ report "Insertion" do
19
+ rbtree { random_array.each_with_index { |x,index| rbtree[index] = x } }
20
+ splaytree { random_array.each_with_index { |x,index| splaytree[index] = x } }
21
+ hash { random_array.each_with_index { |x,index| hash[index] = x } }
22
+ end
23
+
24
+ report "has_key? (linear order)" do
25
+ rbtree { random_array.each { |n| rbtree.has_key?(n) } }
26
+ splaytree { random_array.each { |n| splaytree.has_key?(n) } }
27
+ hash { random_array.each { |n| hash.has_key?(n) } }
28
+ end
29
+
30
+ report "Lookup in sorted order" do
31
+ rbtree { rbtree.each { |k, v| k } }
32
+ splaytree { splaytree.each { |k, v| k } }
33
+ hash { hash.sort.each { |k, v| k } }
34
+
35
+ # a1, a2, a3 = [], [], []
36
+ # rbtree.each { |k, v| a1 << k }
37
+ # splaytree.each { |k, v| a2 << k }
38
+ # hash.sort.each { |k, v| a3 << k }
39
+ #
40
+ # puts "Lookup correct" if a1 == a2 && a1 == a3
41
+ end
42
+
43
+ report "Random lookups in a smaller subset" do
44
+ select_subset = random_array[0..random_array.size/20] # 5%
45
+ size = select_subset.size
46
+ rbtree { 10000.times { rbtree[ select_subset[rand(size)] ] } }
47
+ splaytree { 10000.times { splaytree[ select_subset[rand(size)] ] } }
48
+ hash { 10000.times { hash[ select_subset[rand(size)] ] } }
49
+ end
50
+
51
+ end
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ extension_name = "CString"
3
+ dir_config(extension_name)
4
+ create_makefile(extension_name)
@@ -0,0 +1,68 @@
1
+ #include "ruby.h"
2
+
3
+ int min(int a, int b, int c) {
4
+ int min = a;
5
+ if (b < min)
6
+ min = b;
7
+ if( c < min)
8
+ min = c;
9
+ return min;
10
+ }
11
+
12
+ int levenshtein_distance(VALUE str1, VALUE str2) {
13
+ int i, j, s1_len, s2_len, *d;
14
+ char * s = RSTRING(str1)->ptr;
15
+ char * t = RSTRING(str2)->ptr;
16
+ s1_len = RSTRING(str1)->len;
17
+ s2_len = RSTRING(str2)->len;
18
+
19
+ if (s1_len == 0) {
20
+ return s2_len;
21
+ } else if (s2_len == 0) {
22
+ return s1_len;
23
+ }
24
+
25
+ // We need one extra col and row for the matrix for starting values
26
+ s1_len++;
27
+ s2_len++;
28
+
29
+ d = malloc(sizeof(int) * (s1_len) * (s2_len));
30
+
31
+ for (i = 0; i < s1_len; i++) {
32
+ d[i] = i; // d[i, 0] = i
33
+ }
34
+ for (j = 0; j < s2_len; j++) {
35
+ d[j*s1_len] = j; // d[0, j] = j
36
+ }
37
+
38
+ for (i = 1; i < s1_len; i++) {
39
+ for (j = 1; j < s2_len; j++) {
40
+ if (s[i-1] == t[j-1]) {
41
+ d[j * s1_len + i] = d[(j-1) * s1_len + (i-1)];
42
+ } else {
43
+ d[j * s1_len + i] = min(
44
+ d[j * s1_len + (i-1)],
45
+ d[(j-1) * s1_len + i],
46
+ d[(j-1) * s1_len + (i-1)]
47
+ ) + 1;
48
+ }
49
+ }
50
+ }
51
+ i = d[s1_len * s2_len -1];
52
+ free(d);
53
+ return i;
54
+ }
55
+
56
+ static VALUE lev_dist(VALUE self, VALUE str1, VALUE str2) {
57
+ return INT2FIX(levenshtein_distance( str1, str2 ));
58
+ }
59
+
60
+ static VALUE mAlgorithms;
61
+ static VALUE mString;
62
+
63
+ void Init_CString() {
64
+ mAlgorithms = rb_define_module("Algorithms");
65
+ mString = rb_define_module_under(mAlgorithms, "String");
66
+ rb_define_singleton_method(mString, "levenshtein_dist", lev_dist, 2);
67
+ }
68
+
@@ -0,0 +1,247 @@
1
+ #include "ruby.h"
2
+
3
+ typedef struct struct_bst_node {
4
+ VALUE key;
5
+ VALUE value;
6
+ struct struct_bst_node *left;
7
+ struct struct_bst_node *right;
8
+ struct struct_bst_node *parent;
9
+ } bst_node;
10
+
11
+ typedef struct struct_bst {
12
+ bst_node *root;
13
+ int (*compare_function)(VALUE key1, VALUE key2);
14
+ unsigned int size;
15
+ } bst;
16
+
17
+ static VALUE bst_initialize(VALUE self) {
18
+ return self;
19
+ }
20
+
21
+ static bst* get_bst_from_self(VALUE self) {
22
+ bst *tree;
23
+ Data_Get_Struct(self, bst, tree);
24
+ return tree;
25
+ }
26
+
27
+ static bst* bst_each_node(bst *tree, bst_node *node, void (*each)(bst *tree_, bst_node *node_, void* args), void* arguments) {
28
+ if (!node)
29
+ return NULL;
30
+
31
+ if (node->left)
32
+ bst_each_node(tree, node->left, each, arguments);
33
+
34
+ (*each)(tree, node, arguments);
35
+
36
+ if (node->right)
37
+ bst_each_node(tree, node->right, each, arguments);
38
+ return tree;
39
+ }
40
+
41
+ static bst* bst_each(bst *tree, void (*each)(bst *tree, bst_node *node, void *args), void* arguments) {
42
+ if (tree->root)
43
+ bst_each_node(tree, tree->root, each, arguments);
44
+ return tree;
45
+ }
46
+
47
+ static int id_compare_operator;
48
+
49
+ static int bst_compare_function(VALUE a, VALUE b) {
50
+ if (a == b) return 0;
51
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
52
+ long x = FIX2LONG(a), y = FIX2LONG(b);
53
+ if (x == y) return 0;
54
+ if (x > y) return 1;
55
+ return -1;
56
+ }
57
+ if (TYPE(a) == T_STRING && rb_obj_is_kind_of(a, rb_cString) &&
58
+ TYPE(b) == T_STRING && rb_obj_is_kind_of(b, rb_cString)) {
59
+ return rb_str_cmp(a, b);
60
+ }
61
+ return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
62
+ }
63
+
64
+ static void insert_element(bst *tree, bst_node **t,bst_node *newElement) {
65
+ int cmp;
66
+ bst_node *y = NULL;
67
+ bst_node *x = *t;
68
+ while (x != NULL) {
69
+ y = x;
70
+ cmp = tree->compare_function(newElement->key, x->key);
71
+ if (cmp < 0) x = x->left;
72
+ else x = x->right;
73
+ }
74
+ newElement->parent = y;
75
+ if (y == NULL) *t = newElement;
76
+ else {
77
+ cmp = tree->compare_function(newElement->key, y->key);
78
+ if (cmp < 0)
79
+ y->left = newElement;
80
+ else
81
+ y->right = newElement;
82
+ }
83
+ }
84
+
85
+
86
+ static bst_node* create_node(VALUE key_value,VALUE value) {
87
+ bst_node *new_node = ALLOC(bst_node);
88
+ new_node->value = value;
89
+ new_node->key = key_value;
90
+ new_node->left = NULL;
91
+ new_node->right = NULL;
92
+ new_node->parent = NULL;
93
+ return new_node;
94
+ }
95
+
96
+ static bst_node* tree_minimum (bst_node *tree) {
97
+ bst_node *x = tree;
98
+ while (x->left) x = x->left;
99
+ return x;
100
+ }
101
+
102
+ static bst_node* tree_maximum (bst_node *tree) {
103
+ bst_node *x = tree;
104
+ while (x->right) x = x->right;
105
+ return x;
106
+ }
107
+
108
+ static bst_node* node_successor (bst_node *tree,bst_node *x) {
109
+ if (x->right) return tree_minimum(x->right);
110
+ bst_node *y = x->parent;
111
+ while (y && x == y->right) {
112
+ x = y;
113
+ y = x->parent;
114
+ }
115
+ return y;
116
+ }
117
+
118
+
119
+ static bst_node* delete_node (bst_node **tree,bst_node *tobeDeleted) {
120
+ bst_node *y,*x;
121
+
122
+ if ((tobeDeleted->left == NULL) || (tobeDeleted->right == NULL)) y = tobeDeleted;
123
+ else y = node_successor(*tree,tobeDeleted);
124
+
125
+ if (y->left) x = y->left;
126
+ else x = y->right;
127
+
128
+ if (x) x->parent = y->parent;
129
+
130
+ if (y->parent == NULL) {
131
+ *tree = x;
132
+ return y;
133
+ } else if (y == y->parent->left) {
134
+ y->parent->left = x;
135
+ } else {
136
+ y->parent->right = x;
137
+ }
138
+
139
+ if (tobeDeleted != y) tobeDeleted->key = y->key;
140
+ return y;
141
+ }
142
+
143
+ static bst_node* search_node(bst *tree, bst_node *node, VALUE key) {
144
+ bst_node *x = node;
145
+ int cmp;
146
+
147
+ while(x) {
148
+ cmp = tree->compare_function(key, x->key);
149
+ if (cmp == 0) return x;
150
+ else if (cmp < 0) { x = x->left; }
151
+ else { x = x->right; }
152
+ }
153
+ return NULL;
154
+ }
155
+
156
+ static void recursively_mark_nodes(bst_node *node) {
157
+ if(node) {
158
+ rb_gc_mark(node->key);
159
+ rb_gc_mark(node->value);
160
+ recursively_mark_nodes(node->left);
161
+ recursively_mark_nodes(node->right);
162
+ }
163
+ }
164
+
165
+ static void bst_mark(bst *tree) {
166
+ if (tree) {
167
+ recursively_mark_nodes(tree->root);
168
+ }
169
+ }
170
+
171
+ static void recursively_free_nodes(bst_node *node) {
172
+ if(node) {
173
+ recursively_free_nodes(node->left);
174
+ recursively_free_nodes(node->right);
175
+ free(node);
176
+ }
177
+ }
178
+
179
+ static void bst_free(bst *tree) {
180
+ if (tree) {
181
+ recursively_free_nodes(tree->root);
182
+ }
183
+ }
184
+
185
+ static bst* create_bst(int (*compare_function)(VALUE, VALUE)) {
186
+ bst *tree = ALLOC(bst);
187
+ tree->compare_function = compare_function;
188
+ tree->root = NULL;
189
+ tree->size = 0;
190
+ return tree;
191
+ }
192
+
193
+ static VALUE bst_alloc(VALUE klass) {
194
+ bst *tree = create_bst(&bst_compare_function);
195
+ return Data_Wrap_Struct(klass, bst_mark, bst_free, tree);
196
+ }
197
+
198
+ static VALUE rb_bst_push_value(VALUE self, VALUE key, VALUE value) {
199
+ bst *tree = get_bst_from_self(self);
200
+ insert_element(tree, &(tree->root), create_node(key,value));
201
+ tree->size++;
202
+ return self;
203
+ }
204
+
205
+ static void bst_each_helper(bst *tree, bst_node *node, void *args) {
206
+ rb_yield(rb_ary_new3(2, node->key, node->value));
207
+ };
208
+
209
+ static VALUE rb_bst_each(VALUE self) {
210
+ bst *tree = get_bst_from_self(self);
211
+ bst_each(tree, &bst_each_helper, NULL);
212
+ return self;
213
+ }
214
+
215
+ static VALUE rb_bst_delete(VALUE self, VALUE key) {
216
+ bst *tree = get_bst_from_self(self);
217
+ bst_node *tobeDeleted = search_node(tree, tree->root, key);
218
+ if(tobeDeleted) {
219
+ tree->size -= 1;
220
+ bst_node *deletedNode = delete_node(&(tree->root),tobeDeleted);
221
+ return deletedNode->value;
222
+ }
223
+ return Qnil;
224
+ }
225
+
226
+ static VALUE rb_bst_size(VALUE self) {
227
+ bst *tree;
228
+ Data_Get_Struct(self,bst,tree);
229
+ return INT2FIX(tree->size);
230
+ }
231
+
232
+ static VALUE CBst;
233
+ static VALUE mContainers;
234
+
235
+ void Init_CBst() {
236
+ id_compare_operator = rb_intern("<=>");
237
+
238
+ mContainers = rb_define_module("Containers");
239
+ CBst = rb_define_class_under(mContainers, "CBst", rb_cObject);
240
+ rb_define_alloc_func(CBst, bst_alloc);
241
+ rb_define_method(CBst, "initialize", bst_initialize, 0);
242
+ rb_define_method(CBst, "push", rb_bst_push_value, 2);
243
+ rb_define_alias(CBst, "[]=", "push");
244
+ rb_define_method(CBst, "each", rb_bst_each, 0);
245
+ rb_define_method(CBst, "delete", rb_bst_delete, 1);
246
+ rb_define_method(CBst, "size", rb_bst_size, 0);
247
+ }