stakach-algorithms 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.markdown +99 -97
  2. data/Rakefile +15 -27
  3. data/ext/algorithms/string/extconf.rb +4 -4
  4. data/ext/algorithms/string/string.c +68 -70
  5. data/ext/containers/bst/bst.c +249 -249
  6. data/ext/containers/bst/extconf.rb +4 -4
  7. data/ext/containers/deque/deque.c +248 -248
  8. data/ext/containers/deque/extconf.rb +4 -4
  9. data/ext/containers/rbtree_map/extconf.rb +4 -4
  10. data/ext/containers/rbtree_map/rbtree.c +500 -500
  11. data/ext/containers/splaytree_map/extconf.rb +4 -4
  12. data/ext/containers/splaytree_map/splaytree.c +421 -421
  13. data/lib/algorithms.rb +69 -69
  14. data/lib/algorithms/search.rb +85 -85
  15. data/lib/algorithms/sort.rb +242 -242
  16. data/lib/algorithms/string.rb +10 -10
  17. data/lib/algorithms/version.rb +3 -3
  18. data/lib/containers/deque.rb +176 -176
  19. data/lib/containers/heap.rb +501 -506
  20. data/lib/containers/kd_tree.rb +112 -112
  21. data/lib/containers/priority_queue.rb +116 -116
  22. data/lib/containers/queue.rb +71 -71
  23. data/lib/containers/rb_tree_map.rb +402 -402
  24. data/lib/containers/splay_tree_map.rb +273 -273
  25. data/lib/containers/stack.rb +70 -70
  26. data/lib/containers/suffix_array.rb +71 -71
  27. data/lib/containers/trie.rb +187 -187
  28. data/spec/bst_gc_mark_spec.rb +25 -0
  29. data/spec/bst_spec.rb +25 -0
  30. data/spec/deque_gc_mark_spec.rb +17 -0
  31. data/spec/deque_spec.rb +107 -0
  32. data/spec/heap_spec.rb +130 -0
  33. data/spec/helper.rb +4 -0
  34. data/spec/kd_expected_out.txt +10000 -0
  35. data/spec/kd_test_in.txt +10000 -0
  36. data/spec/kd_tree_spec.rb +33 -0
  37. data/spec/map_gc_mark_spec.rb +28 -0
  38. data/spec/priority_queue_spec.rb +74 -0
  39. data/spec/queue_spec.rb +60 -0
  40. data/spec/rb_tree_map_spec.rb +122 -0
  41. data/spec/search_spec.rb +27 -0
  42. data/spec/sort_spec.rb +26 -0
  43. data/spec/splay_tree_map_spec.rb +105 -0
  44. data/spec/stack_spec.rb +59 -0
  45. data/spec/string_spec.rb +12 -0
  46. data/spec/suffix_array_spec.rb +39 -0
  47. data/spec/trie_spec.rb +58 -0
  48. metadata +60 -4
data/README.markdown CHANGED
@@ -1,97 +1,99 @@
1
- # algorithms
2
-
3
- * Official homes are here on github, and at [rubyforge](http://rubyforge.org/projects/algorithms/)
4
- * Documentation: [http://algorithms.rubyforge.org/](http://algorithms.rubyforge.org/)
5
-
6
- ## DESCRIPTION:
7
-
8
- Started as a [Google Summer of Code 2008](http://code.google.com/soc/2008/ruby/about.html) project
9
-
10
- Written by [Kanwei Li](http://kanwei.com/), mentored by Austin Ziegler
11
-
12
- Original Proposal: Using the right data structure or algorithm for the situation is an important
13
- aspect of programming. In computer science literature, many data structures
14
- and algorithms have been researched and extensively documented. However, there
15
- is still no standard library in Ruby implementing useful structures and
16
- algorithms like Red/Black Trees, tries, different sorting algorithms, etc.
17
- This project will create such a library with documentation on when to use a
18
- particular structure/algorithm. It will also come with a benchmark suite to
19
- compare performance in different situations.
20
-
21
- ## FEATURES:
22
-
23
- Done so far:
24
-
25
- * Heaps Algorithms::Containers::Heap, Containers::MaxHeap, Containers::MinHeap
26
- * Priority Queue Algorithms::Containers::PriorityQueue
27
- * Deque Algorithms::Containers::Deque, Containers::CDeque (C extension), Containers::RubyDeque
28
- * Stack Algorithms::Containers::Stack (uses Deque)
29
- * Queue Algorithms::Containers::Queue (uses Deque)
30
- * Red-Black Trees Algorithms::Containers::RBTreeMap, Containers::CRBTreeMap (C extension), Containers::RubyRBTreeMap
31
- * Splay Trees Algorithms::Containers::SplayTreeMap, Containers::CSplayTreeMap (C extension), Containers::RubySplayTreeMap
32
- * Tries Algorithms::Containers::Trie
33
- * Suffix Array Algorithms::Containers::SuffixArray
34
- * kd Tree Algorithms::Containers::KDTree
35
-
36
- * Search algorithms
37
- - Binary Search Algorithms::Algorithms::Search.binary_search
38
- - Knuth-Morris-Pratt Algorithms::Algorithms::Search.kmp_search
39
- * Sort algorithms
40
- - Bubble sort Algorithms::Algorithms::Sort.bubble_sort
41
- - Comb sort Algorithms::Algorithms::Sort.comb_sort
42
- - Selection sort Algorithms::Algorithms::Sort.selection_sort
43
- - Heapsort Algorithms::Algorithms::Sort.heapsort
44
- - Insertion sort Algorithms::Algorithms::Sort.insertion_sort
45
- - Shell sort Algorithms::Algorithms::Sort.shell_sort
46
- - Quicksort Algorithms::Algorithms::Sort.quicksort
47
- - Mergesort Algorithms::Algorithms::Sort.mergesort
48
-
49
- ## SYNOPSIS:
50
-
51
- require 'rubygems'
52
- require 'algorithms'
53
- max_heap = Algorithms::Containers::MaxHeap.new
54
-
55
- # To not have to type "Algorithms::" before each class, use:
56
- include Algorithms
57
-
58
- max_heap = Containers::MaxHeap.new
59
-
60
- # To not have to type "Containers::" before each class, use:
61
- include Containers
62
- max_heap = MaxHeap.new
63
-
64
-
65
- ## REQUIREMENTS:
66
-
67
- * Ruby 1.8 compatible Ruby, or Ruby 1.9, should also work with jRuby
68
- * C compiler for C extensions (optional, but very much recommended for vast performance benefits)
69
-
70
- ## INSTALL:
71
-
72
- * sudo gem install stakach-algorithms
73
-
74
- ## LICENSE:
75
-
76
- (The MIT License)
77
-
78
- Algorithms and Containers project is Copyright (c) 2009 Kanwei Li
79
-
80
- Permission is hereby granted, free of charge, to any person obtaining
81
- a copy of this software and associated documentation files (the
82
- 'Software'), to deal in the Software without restriction, including
83
- without limitation the rights to use, copy, modify, merge, publish,
84
- distribute, sublicense, and/or sell copies of the Software, and to
85
- permit persons to whom the Software is furnished to do so, subject to
86
- the following conditions:
87
-
88
- The above copyright notice and this permission notice shall be
89
- included in all copies or substantial portions of the Software.
90
-
91
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
92
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
93
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
94
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
95
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
96
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
97
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ # algorithms
2
+
3
+ [![build status](https://secure.travis-ci.org/stakach/algorithms.png)](http://travis-ci.org/stakach/algorithms)
4
+
5
+ * Official homes are here on github, and at [RubyGems](https://rubygems.org/gems/stakach-algorithms)
6
+ * Documentation: [http://algorithms.rubyforge.org/](http://algorithms.rubyforge.org/)
7
+
8
+ ## DESCRIPTION:
9
+
10
+ Started as a Google Summer of Code 2008 project
11
+
12
+ Written by [Kanwei Li](http://kanwei.com/), mentored by Austin Ziegler
13
+
14
+ Original Proposal: Using the right data structure or algorithm for the situation is an important
15
+ aspect of programming. In computer science literature, many data structures
16
+ and algorithms have been researched and extensively documented. However, there
17
+ is still no standard library in Ruby implementing useful structures and
18
+ algorithms like Red/Black Trees, tries, different sorting algorithms, etc.
19
+ This project will create such a library with documentation on when to use a
20
+ particular structure/algorithm. It will also come with a benchmark suite to
21
+ compare performance in different situations.
22
+
23
+ ## FEATURES:
24
+
25
+ Done so far:
26
+
27
+ * Heaps Algorithms::Containers::Heap, Containers::MaxHeap, Containers::MinHeap
28
+ * Priority Queue Algorithms::Containers::PriorityQueue
29
+ * Deque Algorithms::Containers::Deque, Containers::CDeque (C extension), Containers::RubyDeque
30
+ * Stack Algorithms::Containers::Stack (uses Deque)
31
+ * Queue Algorithms::Containers::Queue (uses Deque)
32
+ * Red-Black Trees Algorithms::Containers::RBTreeMap, Containers::CRBTreeMap (C extension), Containers::RubyRBTreeMap
33
+ * Splay Trees Algorithms::Containers::SplayTreeMap, Containers::CSplayTreeMap (C extension), Containers::RubySplayTreeMap
34
+ * Tries Algorithms::Containers::Trie
35
+ * Suffix Array Algorithms::Containers::SuffixArray
36
+ * kd Tree Algorithms::Containers::KDTree
37
+
38
+ * Search algorithms
39
+ - Binary Search Algorithms::Algorithms::Search.binary_search
40
+ - Knuth-Morris-Pratt Algorithms::Algorithms::Search.kmp_search
41
+ * Sort algorithms
42
+ - Bubble sort Algorithms::Algorithms::Sort.bubble_sort
43
+ - Comb sort Algorithms::Algorithms::Sort.comb_sort
44
+ - Selection sort Algorithms::Algorithms::Sort.selection_sort
45
+ - Heapsort Algorithms::Algorithms::Sort.heapsort
46
+ - Insertion sort Algorithms::Algorithms::Sort.insertion_sort
47
+ - Shell sort Algorithms::Algorithms::Sort.shell_sort
48
+ - Quicksort Algorithms::Algorithms::Sort.quicksort
49
+ - Mergesort Algorithms::Algorithms::Sort.mergesort
50
+
51
+ ## SYNOPSIS:
52
+
53
+ require 'rubygems'
54
+ require 'algorithms'
55
+ max_heap = Algorithms::Containers::MaxHeap.new
56
+
57
+ # To not have to type "Algorithms::" before each class, use:
58
+ include Algorithms
59
+
60
+ max_heap = Containers::MaxHeap.new
61
+
62
+ # To not have to type "Containers::" before each class, use:
63
+ include Containers
64
+ max_heap = MaxHeap.new
65
+
66
+
67
+ ## REQUIREMENTS:
68
+
69
+ * Ruby 1.8 compatible Ruby, or Ruby 1.9, should also work with jRuby
70
+ * C compiler for C extensions (optional, but very much recommended for vast performance benefits)
71
+
72
+ ## INSTALL:
73
+
74
+ * sudo gem install stakach-algorithms
75
+
76
+ ## LICENSE:
77
+
78
+ (The MIT License)
79
+
80
+ Algorithms and Containers project is Copyright (c) 2009 Kanwei Li
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining
83
+ a copy of this software and associated documentation files (the
84
+ 'Software'), to deal in the Software without restriction, including
85
+ without limitation the rights to use, copy, modify, merge, publish,
86
+ distribute, sublicense, and/or sell copies of the Software, and to
87
+ permit persons to whom the Software is furnished to do so, subject to
88
+ the following conditions:
89
+
90
+ The above copyright notice and this permission notice shall be
91
+ included in all copies or substantial portions of the Software.
92
+
93
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
94
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
95
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
96
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
97
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
98
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
99
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,27 +1,15 @@
1
- require 'echoe'
2
- require "rake/clean"
3
- OBJ = FileList['**/*.rbc']
4
- CLEAN.include(OBJ)
5
-
6
- Echoe.new('algorithms') do |p|
7
- p.author = 'Kanwei Li'
8
- p.email = 'kanwei@gmail.com'
9
- p.summary = 'A library of algorithms and containers.'
10
- p.url = 'http://rubyforge.org/projects/algorithms/'
11
- p.version = "0.2.0"
12
- p.runtime_dependencies = []
13
- end
14
-
15
- task :push do
16
- sh "git push" # Rubyforge
17
- sh "git push --tags" # Rubyforge
18
- sh "git push gh" # Github
19
- sh "git push gh --tags" # Github
20
- end
21
-
22
- task :hanna do
23
- sh "rm -fr doc"
24
- sh "hanna -SN lib/ -m Algorithms"
25
- sh "scp -rq doc/* kanwei@rubyforge.org:/var/www/gforge-projects/algorithms"
26
- end
27
-
1
+ require "rake/clean"
2
+ require 'rake/extensiontask'
3
+
4
+ OBJ = FileList['**/*.rbc']
5
+ CLEAN.include(OBJ)
6
+
7
+
8
+ Rake::ExtensionTask.new('algorithms/string')
9
+ Rake::ExtensionTask.new('containers/bst')
10
+ Rake::ExtensionTask.new('containers/deque')
11
+ Rake::ExtensionTask.new('containers/rbtree_map')
12
+ Rake::ExtensionTask.new('containers/splaytree_map')
13
+
14
+
15
+
@@ -1,4 +1,4 @@
1
- require 'mkmf'
2
- extension_name = "CString"
3
- dir_config(extension_name)
4
- create_makefile(extension_name)
1
+ require 'mkmf'
2
+ extension_name = "CString"
3
+ dir_config(extension_name)
4
+ create_makefile(extension_name)
@@ -1,70 +1,68 @@
1
- #include "ruby.h"
2
-
3
- int get_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_PTR(str1);
15
- char * t = RSTRING_PTR(str2);
16
- s1_len = RSTRING_LEN(str1);
17
- s2_len = RSTRING_LEN(str2);
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] = get_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 namespace;
61
- static VALUE mAlgorithms;
62
- static VALUE mString;
63
-
64
- void Init_CString() {
65
- namespace = rb_define_module("Algorithms");
66
- mAlgorithms = rb_define_module_under(namespace,"Algorithms");
67
- mString = rb_define_module_under(mAlgorithms, "String");
68
- rb_define_singleton_method(mString, "levenshtein_dist", lev_dist, 2);
69
- }
70
-
1
+ #include "ruby.h"
2
+
3
+ long min_three(long a, long b, long c) {
4
+ long min = a;
5
+ if (b < min)
6
+ min = b;
7
+ if( c < min)
8
+ min = c;
9
+ return min;
10
+ }
11
+
12
+ long levenshtein_distance(VALUE str1, VALUE str2) {
13
+ long i, j, s1_len, s2_len, *d;
14
+ char * s = RSTRING_PTR(str1);
15
+ char * t = RSTRING_PTR(str2);
16
+ s1_len = RSTRING_LEN(str1);
17
+ s2_len = RSTRING_LEN(str2);
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(typeof(d)) * (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] = 1 + min_three(
44
+ d[j * s1_len + (i-1)],
45
+ d[(j-1) * s1_len + i],
46
+ d[(j-1) * s1_len + (i-1)]
47
+ );
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 LONG2FIX(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
+
@@ -1,249 +1,249 @@
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
- static VALUE namespace;
235
-
236
- void Init_CBst() {
237
- id_compare_operator = rb_intern("<=>");
238
-
239
- namespace = rb_define_module("Algorithms");
240
- mContainers = rb_define_module_under(namespace,"Containers");
241
- CBst = rb_define_class_under(mContainers, "CBst", rb_cObject);
242
- rb_define_alloc_func(CBst, bst_alloc);
243
- rb_define_method(CBst, "initialize", bst_initialize, 0);
244
- rb_define_method(CBst, "push", rb_bst_push_value, 2);
245
- rb_define_alias(CBst, "[]=", "push");
246
- rb_define_method(CBst, "each", rb_bst_each, 0);
247
- rb_define_method(CBst, "delete", rb_bst_delete, 1);
248
- rb_define_method(CBst, "size", rb_bst_size, 0);
249
- }
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 VALUE 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
+ static VALUE namespace;
235
+
236
+ void Init_CBst() {
237
+ id_compare_operator = rb_intern("<=>");
238
+
239
+ namespace = rb_define_module("Algorithms");
240
+ mContainers = rb_define_module_under(namespace,"Containers");
241
+ CBst = rb_define_class_under(mContainers, "CBst", rb_cObject);
242
+ rb_define_alloc_func(CBst, bst_alloc);
243
+ rb_define_method(CBst, "initialize", bst_initialize, 0);
244
+ rb_define_method(CBst, "push", rb_bst_push_value, 2);
245
+ rb_define_alias(CBst, "[]=", "push");
246
+ rb_define_method(CBst, "each", rb_bst_each, 0);
247
+ rb_define_method(CBst, "delete", rb_bst_delete, 1);
248
+ rb_define_method(CBst, "size", rb_bst_size, 0);
249
+ }