algorithms 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +139 -2
  2. data/Manifest +31 -8
  3. data/README +90 -0
  4. data/Rakefile +22 -9
  5. data/algorithms.gemspec +28 -101
  6. data/benchmark.rb +29 -27
  7. data/benchmarks/rbench.rb +16 -0
  8. data/benchmarks/rbench/column.rb +26 -0
  9. data/benchmarks/rbench/group.rb +43 -0
  10. data/benchmarks/rbench/report.rb +53 -0
  11. data/benchmarks/rbench/runner.rb +109 -0
  12. data/benchmarks/rbench/summary.rb +51 -0
  13. data/benchmarks/sorts.rb +33 -0
  14. data/ext/containers/bst/bst.c +205 -0
  15. data/ext/containers/{priority_queue → bst}/extconf.rb +1 -1
  16. data/ext/containers/deque/deque.c +233 -0
  17. data/ext/containers/deque/extconf.rb +4 -0
  18. data/ext/containers/tree_map/extconf.rb +1 -1
  19. data/ext/containers/tree_map/rbtree.c +73 -25
  20. data/lib/algorithms.rb +65 -6
  21. data/lib/algorithms/search.rb +84 -0
  22. data/lib/algorithms/sort.rb +238 -0
  23. data/lib/containers/deque.rb +176 -0
  24. data/lib/containers/heap.rb +451 -111
  25. data/lib/containers/kd_tree.rb +87 -0
  26. data/lib/containers/priority_queue.rb +107 -508
  27. data/lib/containers/queue.rb +62 -23
  28. data/lib/containers/rb_tree_map.rb +398 -0
  29. data/lib/containers/splay_tree_map.rb +274 -0
  30. data/lib/containers/stack.rb +59 -21
  31. data/lib/containers/suffix_array.rb +68 -0
  32. data/lib/containers/trie.rb +182 -0
  33. data/lib/graphs/graph.rb +25 -0
  34. data/spec/bst_spec.rb +31 -0
  35. data/spec/deque_spec.rb +108 -0
  36. data/spec/heap_spec.rb +111 -66
  37. data/spec/kd_tree_spec.rb +89 -0
  38. data/spec/priority_queue_spec.rb +71 -27
  39. data/spec/queue_spec.rb +53 -45
  40. data/spec/rb_tree_map_spec.rb +123 -0
  41. data/spec/search_spec.rb +28 -0
  42. data/spec/sort_spec.rb +28 -0
  43. data/spec/splay_tree_map_spec.rb +102 -0
  44. data/spec/stack_spec.rb +56 -49
  45. data/spec/suffix_array_spec.rb +40 -0
  46. data/spec/trie_spec.rb +59 -0
  47. metadata +54 -32
  48. data/README.txt +0 -58
  49. data/ext/containers/priority_queue/priority_queue.c +0 -948
  50. data/ext/containers/tree_map/Rakefile +0 -4
  51. data/lib/containers/hash.rb +0 -0
  52. data/lib/containers/tree_map.rb +0 -265
  53. data/spec/priority_queue_test.rb +0 -371
  54. data/spec/tree_map_spec.rb +0 -99
@@ -0,0 +1,40 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe "empty suffix array" do
5
+ it "should not initialize with empty string" do
6
+ lambda { Containers::SuffixArray.new("") }.should raise_error
7
+ end
8
+ end
9
+
10
+ describe "non-empty suffix array" do
11
+ before(:each) do
12
+ @s_array = Containers::SuffixArray.new("abracadabra")
13
+ end
14
+
15
+ it "should has_substring? each possible substring" do
16
+ @s_array.has_substring?("a").should be_true
17
+ @s_array.has_substring?("abra").should be_true
18
+ @s_array.has_substring?("abracadabra").should be_true
19
+ @s_array.has_substring?("acadabra").should be_true
20
+ @s_array.has_substring?("adabra").should be_true
21
+ @s_array.has_substring?("bra").should be_true
22
+ @s_array.has_substring?("bracadabra").should be_true
23
+ @s_array.has_substring?("cadabra").should be_true
24
+ @s_array.has_substring?("dabra").should be_true
25
+ @s_array.has_substring?("ra").should be_true
26
+ @s_array.has_substring?("racadabra").should be_true
27
+ end
28
+
29
+ it "should not has_substring? substrings it does not have" do
30
+ @s_array.has_substring?("nope").should be_false
31
+ @s_array.has_substring?(nil).should be_false
32
+ end
33
+
34
+ it "should work with numbers (calls to_s)" do
35
+ number = Containers::SuffixArray.new(123456789)
36
+ number[1].should be_true
37
+ number.has_substring?(12).should be_true
38
+ number.has_substring?(13).should be_false
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe "empty trie" do
5
+ before(:each) do
6
+ @trie = Containers::Trie.new
7
+ end
8
+
9
+ it "should not get or has_key?" do
10
+ @trie.get("anything").should be_nil
11
+ @trie.has_key?("anything").should be_false
12
+ end
13
+
14
+ it "should not have longest_prefix or match wildcards" do
15
+ @trie.wildcard("an*thing").should eql([])
16
+ @trie.longest_prefix("an*thing").should eql("")
17
+ end
18
+ end
19
+
20
+ describe "non-empty trie" do
21
+ before(:each) do
22
+ @trie = Containers::Trie.new
23
+ @trie.push("Hello", "World")
24
+ @trie.push("Hilly", "World")
25
+ @trie.push("Hello, brother", "World")
26
+ @trie.push("Hello, bob", "World")
27
+ end
28
+
29
+ it "should has_key? keys it has" do
30
+ @trie.has_key?("Hello").should be_true
31
+ @trie.has_key?("Hello, brother").should be_true
32
+ @trie.has_key?("Hello, bob").should be_true
33
+ end
34
+
35
+ it "should not has_key? keys it doesn't have" do
36
+ @trie.has_key?("Nope").should be_false
37
+ end
38
+
39
+ it "should get values" do
40
+ @trie.get("Hello").should eql("World")
41
+ end
42
+
43
+ it "should overwrite values" do
44
+ @trie.push("Hello", "John")
45
+ @trie.get("Hello").should eql("John")
46
+ end
47
+
48
+ it "should return longest prefix" do
49
+ @trie.longest_prefix("Hello, brandon").should eql("Hello")
50
+ @trie.longest_prefix("Hel").should eql("")
51
+ @trie.longest_prefix("Hello").should eql("Hello")
52
+ @trie.longest_prefix("Hello, bob").should eql("Hello, bob")
53
+ end
54
+
55
+ it "should match wildcards" do
56
+ @trie.wildcard("H*ll.").should eql(["Hello", "Hilly"])
57
+ @trie.wildcard("Hel").should eql([])
58
+ end
59
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algorithms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kanwei Li
@@ -9,65 +9,87 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-25 00:00:00 -04:00
12
+ date: 2009-02-21 00:00:00 -05:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: echoe
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- version:
14
+ dependencies: []
15
+
25
16
  description: A library of algorithms and containers.
26
17
  email: kanwei@gmail.com
27
18
  executables: []
28
19
 
29
20
  extensions:
30
- - ext/containers/priority_queue/extconf.rb
21
+ - ext/containers/bst/extconf.rb
22
+ - ext/containers/deque/extconf.rb
31
23
  - ext/containers/tree_map/extconf.rb
32
24
  extra_rdoc_files:
33
- - ext/containers/priority_queue/extconf.rb
34
- - ext/containers/priority_queue/priority_queue.c
25
+ - ext/containers/bst/bst.c
26
+ - ext/containers/bst/extconf.rb
27
+ - ext/containers/deque/deque.c
28
+ - ext/containers/deque/extconf.rb
35
29
  - ext/containers/tree_map/extconf.rb
36
- - ext/containers/tree_map/Rakefile
37
30
  - ext/containers/tree_map/rbtree.c
31
+ - lib/algorithms/search.rb
32
+ - lib/algorithms/sort.rb
38
33
  - lib/algorithms.rb
39
- - lib/containers/hash.rb
34
+ - lib/containers/deque.rb
40
35
  - lib/containers/heap.rb
36
+ - lib/containers/kd_tree.rb
41
37
  - lib/containers/priority_queue.rb
42
38
  - lib/containers/queue.rb
39
+ - lib/containers/rb_tree_map.rb
40
+ - lib/containers/splay_tree_map.rb
43
41
  - lib/containers/stack.rb
44
- - lib/containers/tree_map.rb
45
- - README.txt
42
+ - lib/containers/suffix_array.rb
43
+ - lib/containers/trie.rb
44
+ - lib/graphs/graph.rb
45
+ - README
46
46
  files:
47
+ - algorithms.gemspec
47
48
  - benchmark.rb
48
- - ext/containers/priority_queue/extconf.rb
49
- - ext/containers/priority_queue/priority_queue.c
49
+ - benchmarks/rbench/column.rb
50
+ - benchmarks/rbench/group.rb
51
+ - benchmarks/rbench/report.rb
52
+ - benchmarks/rbench/runner.rb
53
+ - benchmarks/rbench/summary.rb
54
+ - benchmarks/rbench.rb
55
+ - benchmarks/sorts.rb
56
+ - ext/containers/bst/bst.c
57
+ - ext/containers/bst/extconf.rb
58
+ - ext/containers/deque/deque.c
59
+ - ext/containers/deque/extconf.rb
50
60
  - ext/containers/tree_map/extconf.rb
51
- - ext/containers/tree_map/Rakefile
52
61
  - ext/containers/tree_map/rbtree.c
53
62
  - History.txt
63
+ - lib/algorithms/search.rb
64
+ - lib/algorithms/sort.rb
54
65
  - lib/algorithms.rb
55
- - lib/containers/hash.rb
66
+ - lib/containers/deque.rb
56
67
  - lib/containers/heap.rb
68
+ - lib/containers/kd_tree.rb
57
69
  - lib/containers/priority_queue.rb
58
70
  - lib/containers/queue.rb
71
+ - lib/containers/rb_tree_map.rb
72
+ - lib/containers/splay_tree_map.rb
59
73
  - lib/containers/stack.rb
60
- - lib/containers/tree_map.rb
74
+ - lib/containers/suffix_array.rb
75
+ - lib/containers/trie.rb
76
+ - lib/graphs/graph.rb
61
77
  - Manifest
62
78
  - Rakefile
63
- - README.txt
79
+ - README
80
+ - spec/bst_spec.rb
81
+ - spec/deque_spec.rb
64
82
  - spec/heap_spec.rb
83
+ - spec/kd_tree_spec.rb
65
84
  - spec/priority_queue_spec.rb
66
- - spec/priority_queue_test.rb
67
85
  - spec/queue_spec.rb
86
+ - spec/rb_tree_map_spec.rb
87
+ - spec/search_spec.rb
88
+ - spec/sort_spec.rb
89
+ - spec/splay_tree_map_spec.rb
68
90
  - spec/stack_spec.rb
69
- - spec/tree_map_spec.rb
70
- - algorithms.gemspec
91
+ - spec/suffix_array_spec.rb
92
+ - spec/trie_spec.rb
71
93
  has_rdoc: true
72
94
  homepage: http://rubyforge.org/projects/algorithms/
73
95
  post_install_message:
@@ -77,7 +99,7 @@ rdoc_options:
77
99
  - --title
78
100
  - Algorithms
79
101
  - --main
80
- - README.txt
102
+ - README
81
103
  require_paths:
82
104
  - lib
83
105
  - ext
@@ -89,14 +111,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
89
111
  version:
90
112
  required_rubygems_version: !ruby/object:Gem::Requirement
91
113
  requirements:
92
- - - "="
114
+ - - ">="
93
115
  - !ruby/object:Gem::Version
94
116
  version: "1.2"
95
117
  version:
96
118
  requirements: []
97
119
 
98
120
  rubyforge_project: algorithms
99
- rubygems_version: 1.2.0
121
+ rubygems_version: 1.3.1
100
122
  signing_key:
101
123
  specification_version: 2
102
124
  summary: A library of algorithms and containers.
data/README.txt DELETED
@@ -1,58 +0,0 @@
1
- = algorithms
2
-
3
- * http://rubyforge.org/projects/algorithms/
4
-
5
- == DESCRIPTION:
6
-
7
- Using the right data structure or algorithm for the situation is an important aspect of programming. In computer science literature, many data structures and algorithms have been researched and extensively documented. However, there is still no standard library in Ruby implementing useful structures and algorithms like Red/Black Trees, tries, graphs, different sorting algorithms, etc. This project will create such a library with documentation on when to use a particular structure/algorithm. It will also come with a benchmark suite to compare performance in different situations.
8
-
9
- == FEATURES/PROBLEMS:
10
-
11
- Done so far:
12
- * Heaps (Maximum, Minimum)
13
- * Priority Queue
14
- * Stack
15
- * Queue
16
- * TreeMap
17
-
18
- == SYNOPSIS:
19
-
20
- require 'rubygems'
21
- require 'algorithms'
22
-
23
- include Containers
24
- max_heap = MaxHeap.new
25
-
26
- == REQUIREMENTS:
27
-
28
- * Ruby 1.8
29
- * C compiler for extensions (optional)
30
-
31
- == INSTALL:
32
-
33
- * sudo gem install
34
-
35
- == LICENSE:
36
-
37
- (The MIT License)
38
-
39
- Copyright (c) 2008 Kanwei Li
40
-
41
- Permission is hereby granted, free of charge, to any person obtaining
42
- a copy of this software and associated documentation files (the
43
- 'Software'), to deal in the Software without restriction, including
44
- without limitation the rights to use, copy, modify, merge, publish,
45
- distribute, sublicense, and/or sell copies of the Software, and to
46
- permit persons to whom the Software is furnished to do so, subject to
47
- the following conditions:
48
-
49
- The above copyright notice and this permission notice shall be
50
- included in all copies or substantial portions of the Software.
51
-
52
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
53
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,948 +0,0 @@
1
- /*
2
- * :main:CPriorityQueue
3
- *
4
- * Ruby extension implementing a priority queue
5
- *
6
- * This is a fibonacci heap priority queue implementation.
7
- *
8
- * (c) 2005 Brian Schr�der
9
- *
10
- * Please submit bugreports to priority_queue@brian-schroeder.de
11
- *
12
- * This extension is under the same license as ruby.
13
- *
14
- * Do not hold me reliable for anything that happens to you, your programs or
15
- * anything else because of this extension. It worked for me, but there is no
16
- * guarantee it will work for you.
17
- *
18
- * Except for using a value except of a void* the priority queue c-code is ruby
19
- * agnostic.
20
- *
21
- * Modifications by Kanwei Li
22
- */
23
- #include <stdlib.h>
24
- #include <stdio.h>
25
- #include "ruby.h"
26
- #include <math.h>
27
-
28
- #define FALSE 0;
29
- #define TRUE 1;
30
-
31
- // Node Structure
32
- typedef struct struct_priority_node {
33
- unsigned int degree;
34
- VALUE priority;
35
- VALUE object;
36
- struct struct_priority_node* parent;
37
- struct struct_priority_node* child;
38
- struct struct_priority_node* left;
39
- struct struct_priority_node* right;
40
- int mark;
41
- } priority_node;
42
-
43
- // The Priority Queue
44
- typedef struct {
45
- priority_node* rootlist;
46
- priority_node* min;
47
- unsigned int length;
48
- int (*compare_function)(VALUE p1, VALUE p2); // Should return < 0 for a < b, 0 for a == b, > 0 for a > b
49
- } priority_queue;
50
-
51
- ////////////////////////////////////////////////////////////////////////////////
52
- // Node Manipulation Functions
53
- ////////////////////////////////////////////////////////////////////////////////
54
-
55
- // Create a priority node structure
56
- priority_node* create_priority_node(VALUE object, VALUE priority) {
57
- priority_node* result = ALLOC(priority_node);
58
- result->degree = 0;
59
- result->priority = priority;
60
- result->object = object;
61
- result->parent = NULL;
62
- result->child = NULL;
63
- result->left = result;
64
- result->right = result;
65
- result->mark = FALSE;
66
- return result;
67
- }
68
-
69
- // Use this to free a node struct
70
- void priority_node_free(priority_node* n) {
71
- free(n);
72
- }
73
-
74
- static
75
- void priority_node_free_recursively(priority_node* n) {
76
- if (!n)
77
- return;
78
-
79
- priority_node* n1 = n;
80
- do {
81
- priority_node *n2 = n1->right;
82
- priority_node_free_recursively(n1->child);
83
- priority_node_free(n1);
84
- n1 = n2;
85
- } while(n1 != n);
86
- }
87
-
88
- // link two binomial heaps
89
- static
90
- priority_node* link_nodes(priority_queue* q, priority_node* b1, priority_node* b2) {
91
- if (q->compare_function(b2->priority, b1->priority) < 0)
92
- return link_nodes(q, b2, b1);
93
- b2->parent = b1;
94
- priority_node* child = b1->child;
95
- b1->child = b2;
96
- if (child) {
97
- b2->left = child->left;
98
- b2->left->right = b2;
99
- b2->right = child;
100
- b2->right->left = b2;
101
- } else {
102
- b2->left = b2;
103
- b2->right = b2;
104
- }
105
- b1->degree++;
106
- b2->mark = FALSE; // TODO: Check if it is not rather b1 that should be marked as false
107
- return b1;
108
- }
109
-
110
- ////////////////////////////////////////////////////////////////////////////////
111
- // Queue Manipulation Functions
112
- ////////////////////////////////////////////////////////////////////////////////
113
-
114
- // Create an empty priority queue
115
- priority_queue* create_priority_queue(int (*compare_function)(VALUE, VALUE)) {
116
- priority_queue *result = ALLOC(priority_queue);
117
- result->min = NULL;
118
- result->rootlist = NULL;
119
- result->length = 0;
120
- result->compare_function = compare_function;
121
- return result;
122
- }
123
-
124
- // Free a priority queue and all the nodes it contains
125
- void priority_queue_free(priority_queue* q) {
126
- priority_node_free_recursively(q->rootlist);
127
- free(q);
128
- }
129
-
130
- // Insert a node into the rootlist
131
- // Does not change length value
132
- static
133
- priority_queue* insert_tree(priority_queue* const q, priority_node* const tree) {
134
- if (q->rootlist) {
135
- priority_node* l = q->rootlist->left;
136
- l->right = tree;
137
- q->rootlist->left = tree;
138
- tree->left = l;
139
- tree->right = q->rootlist;
140
- if (q->compare_function(tree->priority, q->min->priority) < 0)
141
- q->min = tree;
142
- } else {
143
- q->rootlist = tree;
144
- q->min = tree;
145
- }
146
- return q;
147
- }
148
-
149
- // Meld two queues into one new queue. We take the first queue and the rootnode of the second queue. // TODO: Expose in API
150
- static
151
- priority_queue* meld_queue(priority_queue* q1, priority_node* q2, unsigned int length_q2) {
152
- if (!q1->rootlist) {
153
- q1->rootlist = q2;
154
- q1->min = q2;
155
- q1->length = length_q2;
156
- } else {
157
- priority_node* r1 = q1->rootlist->left;
158
- priority_node* r2 = q2->left;
159
-
160
- q1->rootlist->left = r2;
161
- r2->right = q1->rootlist;
162
-
163
- q2->left = r1;
164
- r1->right = q2;
165
-
166
- q1->length = q1->length + length_q2;
167
-
168
- if (q1->compare_function(q2->priority, q1->min->priority) < 0)
169
- q1->min = q2;
170
- }
171
-
172
- return q1;
173
- }
174
-
175
- // Add an object and a priority to a priority queue. Returns a pointer to a
176
- // priority_node structure, which can be used in delete_node and priority_queue_change_priority
177
- // operations.
178
- priority_node* priority_queue_add_node(priority_queue* q, VALUE object, VALUE priority) {
179
- priority_node* result = create_priority_node(object, priority);
180
- insert_tree(q, result);
181
- q->length++;
182
- return result;
183
- }
184
-
185
- // Does not change length
186
- static
187
- priority_node* delete_first(priority_queue* const q) {
188
- if (q->rootlist) {
189
- priority_node* result = q->rootlist;
190
- if (result == result->right)
191
- q->rootlist = NULL;
192
- else {
193
- q->rootlist = result->right;
194
- result->left->right = result->right;
195
- result->right->left = result->left;
196
- result->right = result;
197
- result->left = result;
198
- }
199
- return result;
200
- } else {
201
- return NULL;
202
- }
203
- }
204
-
205
- static
206
- void assert_pointers_correct(priority_node* n) {
207
- if (!n) return;
208
-
209
- priority_node *n1 = n->right;
210
- while(n != n1) {
211
- if (n1->child && (n1 != n1->child->parent))
212
- printf("Eltern-Kind Zeiger inkorrekt: %p\n", n);
213
-
214
- if (n1 != n1->right->left)
215
- printf("Rechts-links inkorrekt: %p\n", n);
216
-
217
- if (n1 != n1->left->right)
218
- printf("links-Rechts inkorrekt: %p\n", n);
219
-
220
- assert_pointers_correct(n1->child);
221
- n1 = n1->right;
222
- }
223
- }
224
-
225
- // Consolidate a queue in amortized O(log n)
226
- static
227
- void consolidate_queue(priority_queue* const q) {
228
- unsigned int array_size = 2 * log(q->length) / log(2) + 1;
229
- priority_node* tree_by_degree[array_size];
230
- unsigned int i;
231
- for (i=0; i<array_size; i++)
232
- tree_by_degree[i] = NULL;
233
-
234
- priority_node* n = NULL;
235
- while (((n = delete_first(q)))) {
236
- priority_node* n1 = NULL;
237
- while (((n1 = tree_by_degree[n->degree]))) {
238
- tree_by_degree[n->degree] = NULL;
239
- n = link_nodes(q, n, n1);
240
- }
241
- tree_by_degree[n->degree] = n;
242
- }
243
-
244
- // Find minimum value in O(log n)
245
- q->rootlist = NULL;
246
- q->min = NULL;
247
- for (i=0; i<array_size; i++) {
248
- if (tree_by_degree[i] != NULL) {
249
- insert_tree(q, tree_by_degree[i]);
250
- }
251
- }
252
- }
253
-
254
- // Delete and extract priority_node with minimal priority O(log n)
255
- priority_node* priority_queue_delete_min(priority_queue* q) {
256
- if (!q->rootlist) return NULL;
257
- priority_node* min = q->min;
258
-
259
- if (q->length == 1){ // length == 1
260
- q->rootlist = NULL;
261
- q->min = NULL;
262
- q->length = 0;
263
- } else {
264
- unsigned int length = q->length;
265
- // Abtrennen.
266
- if (q->min == q->rootlist) {
267
- if (q->min == q->min->right) {
268
- q->rootlist = NULL;
269
- q->min = NULL;
270
- } else {
271
- q->rootlist = q->min->right;
272
- }
273
- }
274
- min->left->right = min->right;
275
- min->right->left = min->left;
276
- min->left = min;
277
- min->right = min;
278
- if (min->child) {
279
- // Kinder und Eltern trennen, Markierung aufheben, und kleinstes Kind bestimmen.
280
- priority_node* n = min->child;
281
- do {
282
- n->parent = NULL;
283
- n->mark = FALSE;
284
- n = n->right;
285
- } while (n!=min->child);
286
-
287
- // Kinder einf�gen
288
- if (q->rootlist) {
289
- priority_node* const l1 = q->rootlist->left;
290
- priority_node* const l2 = n->left;
291
-
292
- l1->right = n;
293
- n->left = l1;
294
- l2->right = q->rootlist;
295
- q->rootlist->left = l2;
296
- } else {
297
- q->rootlist = n;
298
- }
299
- }
300
-
301
- // Gr��e anpassen
302
- q->length = length-1;
303
-
304
- // Wieder aufh�bschen
305
- consolidate_queue(q);
306
- }
307
-
308
- return min;
309
- }
310
-
311
- static
312
- priority_queue* cut_node(priority_queue* q, priority_node* n) {
313
- if (!n->parent)
314
- return q;
315
- n->parent->degree--;
316
- if (n->parent->child == n) {
317
- if (n->right == n)
318
- n->parent->child = NULL;
319
- else
320
- n->parent->child = n->right;
321
- }
322
- n->parent = NULL;
323
- n->right->left = n->left;
324
- n->left->right = n->right;
325
-
326
- n->right = q->rootlist;
327
- n->left = q->rootlist->left;
328
- q->rootlist->left->right = n;
329
- q->rootlist->left = n;
330
- q->rootlist = n;
331
-
332
- n->mark = FALSE;
333
-
334
- return q;
335
- }
336
-
337
- // change the priority of a priority_node and restructure the queue
338
- // Does not free the priority node
339
- priority_queue* priority_queue_delete(priority_queue* q, priority_node* n) {
340
- if (n->child) {
341
- priority_node* c = n->child;
342
- priority_node* e = n->child;
343
- do {
344
- priority_node* r = c->right;
345
- cut_node(q, c);
346
- c = r;
347
- } while (c != e);
348
- }
349
- if (n->parent)
350
- cut_node(q, n);
351
- if (n == n->right) {
352
- q->min = NULL;
353
- q->rootlist = NULL;
354
- } else {
355
- if (q->rootlist == n)
356
- q->rootlist = n->right;
357
- if (q->min == n) {
358
- priority_node* n1 = n->right;
359
- q->min = n1;
360
- do {
361
- if (q->compare_function(n1->priority, q->min->priority) <= 0)
362
- q->min = n1;
363
- n1 = n1->right;
364
- } while(n1 != n);
365
- }
366
- n->right->left = n->left;
367
- n->left->right = n->right;
368
- n->left = n;
369
- n->right = n;
370
- }
371
- q->length -= 1;
372
- return q;
373
- }
374
-
375
- // change the priority of a priority_node and restructure the queue
376
- priority_queue* priority_queue_change_priority(priority_queue* q, priority_node* n, VALUE priority) {
377
- if (q->compare_function(n->priority, priority) <= 0) { // Priority was increased. Remove the node and reinsert.
378
- priority_queue_delete(q, n);
379
- n->priority = priority;
380
- meld_queue(q, n, 1);
381
- return q;
382
- }
383
- n->priority = priority;
384
- if (q->compare_function(n->priority, q->min->priority) < 0)
385
- q->min = n;
386
- if (!(n->parent) || (q->compare_function(n->parent->priority, n->priority) <= 0)) // Already in rootlist or bigger than parent
387
- return q;
388
- do { // Cascading Cuts
389
- priority_node* p = n->parent;
390
- cut_node(q, n);
391
- n = p;
392
- } while (n->mark && n->parent);
393
- if (n->parent)
394
- n->mark = TRUE;
395
- return q;
396
- }
397
-
398
- // Get the priority_node with the minimum priority from a queue
399
- priority_node* priority_queue_min(priority_queue *q) {
400
- return q->min;
401
- }
402
-
403
- int priority_queue_empty(priority_queue *q) {
404
- return q->min == NULL;
405
- }
406
-
407
- // change the priority of a priority_node and restructure the queue
408
- priority_queue* priority_queue_each_node(priority_queue* q, priority_node* n,
409
- void (*each)(priority_queue* q_, priority_node* n_, void* args), void* arguments) {
410
- priority_node* end = n;
411
- do {
412
- priority_node* next = n->right;
413
- (*each)(q, n, arguments);
414
- if (n->child)
415
- priority_queue_each_node(q, n->child, each, arguments);
416
- n = n->right;
417
- if (n != next)
418
- break;
419
- } while (n != end);
420
- return q;
421
- }
422
-
423
- priority_queue* priority_queue_each(priority_queue* q,
424
- void (*each)(priority_queue* q, priority_node* n, void* args), void* arguments) {
425
- if (q->rootlist)
426
- priority_queue_each_node(q, q->rootlist, each, arguments);
427
- return q;
428
- }
429
- ////////////////////////////////////////////////////////////////////////////////
430
- // Define the ruby classes
431
- ////////////////////////////////////////////////////////////////////////////////
432
-
433
- static int id_compare_operator;
434
- static int id_format;
435
- static int id_display;
436
-
437
- priority_queue* get_pq_from_value(VALUE self) {
438
- priority_queue *q;
439
- Data_Get_Struct(self, priority_queue, q);
440
- return q;
441
- }
442
-
443
- static
444
- int priority_compare_function(VALUE a, VALUE b) {
445
- return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
446
- }
447
-
448
- static
449
- void pq_free(void *p) {
450
- priority_queue_free(p);
451
- }
452
-
453
- static
454
- void pq_mark_recursive(priority_node* n) {
455
- if (!n) return;
456
- rb_gc_mark((VALUE) n->object);
457
- rb_gc_mark((VALUE) n->priority);
458
- priority_node* n1 = n->child;
459
- if (!n1) return;
460
- do {
461
- pq_mark_recursive(n1);
462
- n1 = n1->right;
463
- } while (n1 != n->child);
464
- }
465
-
466
- static
467
- void pq_mark(void *q) {
468
- priority_node* n1 = ((priority_queue*) q)->rootlist;
469
- if (!n1)
470
- return;
471
- priority_node* n2 = n1;
472
- do {
473
- pq_mark_recursive(n1);
474
- n1 = n1->right;
475
- } while (n1 != n2);
476
- }
477
-
478
- static
479
- VALUE pq_alloc(VALUE klass) {
480
- priority_queue *q;
481
- VALUE object;
482
-
483
- q = create_priority_queue(&priority_compare_function);
484
-
485
- object = Data_Wrap_Struct(klass, pq_mark, pq_free, q);
486
-
487
- return object;
488
- }
489
-
490
- /*
491
- * Create a new, empty PriorityQueue
492
- */
493
- static
494
- VALUE pq_init(VALUE self) {
495
- rb_iv_set(self, "@__node_by_object__", rb_hash_new());
496
-
497
- return self;
498
- }
499
-
500
- /*
501
- * Add an object to the queue.
502
- */
503
- static
504
- VALUE pq_push(VALUE self, VALUE object, VALUE priority) {
505
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
506
-
507
- priority_queue* q = get_pq_from_value(self);
508
-
509
- priority_node* n = priority_queue_add_node(q, object, priority);
510
-
511
- rb_hash_aset(hash, object, ULONG2NUM((unsigned long) n)); // TODO: This is hackish, maybe its better to also wrap the nodes.
512
-
513
- return self;
514
- }
515
-
516
- /* call-seq:
517
- * min -> [object, priority]
518
- *
519
- * Return the pair [object, priority] with minimal priority or nil when the
520
- * queue is empty.
521
- *
522
- * q = PriorityQueue.new
523
- * q["a"] = 10
524
- * q["b"] = 20
525
- * q.min #=> ["a", 10]
526
- * q.delete_min #=> ["a", 10]
527
- * q.min #=> ["b", 20]
528
- * q.delete_min #=> ["b", 20]
529
- * q.min #=> nil
530
- */
531
- static
532
- VALUE pq_min(VALUE self) {
533
- priority_queue* q = get_pq_from_value(self);
534
-
535
- priority_node* n = priority_queue_min(q);
536
- if (n)
537
- return rb_ary_new3(2, n->object, n->priority);
538
- else
539
- return Qnil;
540
- }
541
-
542
- /* call-seq:
543
- * min_key -> object
544
- *
545
- * Return the key that has the minimal priority or nil when the queue is empty.
546
- *
547
- * q = PriorityQueue.new
548
- * q["a"] = 10
549
- * q["b"] = 20
550
- * q.min_key #=> "a"
551
- * q.delete_min #=> ["a", 10]
552
- * q.min_key #=> "b"
553
- * q.delete_min #=> ["b", 20]
554
- * q.min_key #=> nil
555
- */
556
- static
557
- VALUE pq_min_key(VALUE self) {
558
- priority_queue* q = get_pq_from_value(self);
559
-
560
- priority_node* n = priority_queue_min(q);
561
- if (n)
562
- return n->object;
563
- else
564
- return Qnil;
565
- }
566
-
567
- /* call-seq:
568
- * min_priority -> priority
569
- *
570
- * Return the minimal priority or nil when the queue is empty.
571
- *
572
- * q = PriorityQueue.new
573
- * q["a"] = 10
574
- * q["b"] = 20
575
- * q.min_priority #=> 10
576
- * q.delete_min #=> ["a", 10]
577
- * q.min_priority #=> 20
578
- * q.delete_min #=> ["b", 20]
579
- * q.min_priority #=> nil
580
- */
581
- static
582
- VALUE pq_min_priority(VALUE self) {
583
- priority_queue* q = get_pq_from_value(self);
584
-
585
- priority_node* n = priority_queue_min(q);
586
- if (n)
587
- return n->priority;
588
- else
589
- return Qnil;
590
- }
591
-
592
- /* call-seq:
593
- * delete_min -> [key, priority]
594
- *
595
- * Delete key with minimal priority and return [key, priority]
596
- *
597
- * q = PriorityQueue.new
598
- * q["a"] = 1
599
- * q["b"] = 0
600
- * q.delete_min #=> ["b", 0]
601
- * q.delete_min #=> ["a", 1]
602
- * q.delete_min #=> nil
603
- */
604
- static
605
- VALUE pq_delete_min(VALUE self) {
606
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
607
- priority_queue* q = get_pq_from_value(self);
608
-
609
- priority_node* n = priority_queue_delete_min(q);
610
-
611
- if (n) {
612
- rb_hash_delete(hash, n->object); // TODO: Maybe we have a problem here with garbage collection of n->object?
613
- return rb_ary_new3(2, n->object, n->priority);
614
- } else {
615
- return Qnil;
616
- }
617
- }
618
-
619
- /* call-seq:
620
- * delete_min_return_key -> key
621
- *
622
- * Delete key with minimal priority and return the key
623
- *
624
- * q = PriorityQueue.new
625
- * q["a"] = 1
626
- * q["b"] = 0
627
- * q.delete_min_return_key #=> "b"
628
- * q.delete_min_return_key #=> "a"
629
- * q.delete_min_return_key #=> nil
630
- */
631
- static
632
- VALUE pq_delete_min_return_key(VALUE self) {
633
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
634
- priority_queue* q = get_pq_from_value(self);
635
-
636
- priority_node* n = priority_queue_delete_min(q);
637
-
638
- if (n) {
639
- rb_hash_delete(hash, n->object); // TODO: Maybe we have a problem here with garbage collection of n->object?
640
- return n->object;
641
- } else {
642
- return Qnil;
643
- }
644
- }
645
-
646
- /*
647
- * call-seq:
648
- * delete_min_return_priority -> priority
649
- *
650
- * Delete key with minimal priority and return the priority value
651
- *
652
- * q = PriorityQueue.new
653
- * q["a"] = 1
654
- * q["b"] = 0
655
- * q.delete_min_return_priority #=> 0
656
- * q.delete_min_return_priority #=> 1
657
- * q.delete_min_return_priority #=> nil
658
- */
659
- static
660
- VALUE pq_delete_min_return_priority(VALUE self) {
661
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
662
- priority_queue* q = get_pq_from_value(self);
663
-
664
- priority_node* n = priority_queue_delete_min(q);
665
-
666
- if (n) {
667
- rb_hash_delete(hash, n->object); // TODO: Maybe we have a problem here with garbage collection of n->object?
668
- return n->priority;
669
- } else {
670
- return Qnil;
671
- }
672
- }
673
-
674
- /*
675
- * call-seq:
676
- * [key] = priority
677
- * change_priority(key, priority)
678
- * push(key, priority)
679
- *
680
- * Set the priority of a key.
681
- *
682
- * q = PriorityQueue.new
683
- * q["car"] = 50
684
- * q["train"] = 50
685
- * q["bike"] = 10
686
- * q.min #=> ["bike", 10]
687
- * q["car"] = 0
688
- * q.min #=> ["car", 0]
689
- */
690
- static
691
- VALUE pq_change_priority(VALUE self, VALUE object, VALUE priority) {
692
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
693
- priority_queue* q = get_pq_from_value(self);
694
-
695
- VALUE node = rb_hash_aref(hash, object);
696
- if (NIL_P(node)) {
697
- pq_push(self, object, priority);
698
- } else {
699
- priority_queue_change_priority(q, (priority_node*) NUM2ULONG(node), priority);
700
- }
701
-
702
- return self;
703
- }
704
-
705
- /*
706
- * call-seq:
707
- * [key] -> priority
708
- *
709
- * Return the priority of a key or nil if the key is not in the queue.
710
- *
711
- * q = PriorityQueue.new
712
- * (0..10).each do | i | q[i.to_s] = i end
713
- * q["5"] #=> 5
714
- * q[5] #=> nil
715
- */
716
- static
717
- VALUE pq_get_priority(VALUE self, VALUE object) {
718
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
719
-
720
- VALUE node_pointer = rb_hash_aref(hash, object);
721
-
722
- if (NIL_P(node_pointer))
723
- return Qnil;
724
- else
725
- return (VALUE) (((priority_node*) NUM2ULONG(node_pointer))->priority);
726
- }
727
-
728
- /*
729
- * call-seq:
730
- * has_key? key -> boolean
731
- *
732
- * Return false if the key is not in the queue, true otherwise.
733
- *
734
- * q = PriorityQueue.new
735
- * (0..10).each do | i | q[i.to_s] = i end
736
- * q.has_key("5") #=> true
737
- * q.has_key(5) #=> false
738
- */
739
- static
740
- VALUE pq_has_key(VALUE self, VALUE object) {
741
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
742
-
743
- VALUE node_pointer = rb_hash_aref(hash, object);
744
-
745
- return NIL_P(node_pointer) ? Qfalse : Qtrue;
746
- }
747
- /* call-seq:
748
- * length -> Fixnum
749
- *
750
- * Returns the number of elements of the queue.
751
- *
752
- * q = PriorityQueue.new
753
- * q.length #=> 0
754
- * q[0] = 1
755
- * q.length #=> 1
756
- */
757
- static
758
- VALUE pq_length(VALUE self) {
759
- priority_queue* q = get_pq_from_value(self);
760
-
761
- return INT2NUM(q->length);
762
- }
763
-
764
- /* call-seq:
765
- * delete(key) -> [key, priority]
766
- * delete(key) -> nil
767
- *
768
- * Delete a key from the priority queue. Returns nil when the key was not in
769
- * the queue and [key, priority] otherwise.
770
- *
771
- * q = PriorityQueue.new
772
- * (0..10).each do | i | q[i.to_s] = i end
773
- * q.delete(5) #=> ["5", 5]
774
- * q.delete(5) #=> nil
775
- */
776
- static
777
- VALUE pq_delete(VALUE self, VALUE object) {
778
- priority_queue* q = get_pq_from_value(self);
779
-
780
- VALUE hash = rb_iv_get(self, "@__node_by_object__");
781
-
782
- VALUE node_pointer = rb_hash_aref(hash, object);
783
-
784
- if (NIL_P(node_pointer))
785
- return Qnil;
786
- else {
787
- priority_node* n = (priority_node*) NUM2ULONG(node_pointer);
788
- VALUE object = n->object;
789
- VALUE priority = n->priority;
790
- priority_queue_delete(q, n);
791
- rb_hash_delete(hash, object);
792
- priority_node_free(n);
793
- return rb_ary_new3(2, object, priority);
794
- }
795
- }
796
-
797
-
798
- // Dot a single node of a priority queue. Called by pq_to_dot to do the inner work.
799
- // (I'm not proud of this function ;-( )
800
- static
801
- void pq_node2dot(VALUE result_string, priority_node* n, unsigned int level) {
802
- if (n == NULL) return;
803
- unsigned int i;
804
- for (i=0; i<level; i++) rb_str_cat2(result_string, " ");
805
- if (n->mark)
806
- rb_str_concat(result_string,
807
- rb_funcall(Qnil, id_format, 4, rb_str_new2("NODE%i [label=\"%s (%s)\"];\n"),
808
- ULONG2NUM((unsigned long) n), n->object, n->priority));
809
- else
810
- rb_str_concat(result_string,
811
- rb_funcall(Qnil, id_format, 4, rb_str_new2("NODE%i [label=\"%s (%s)\",shape=box];\n"),
812
- ULONG2NUM((unsigned long) n), n->object, n->priority));
813
- if (n->child != NULL) {
814
- priority_node* n1 = n->child;
815
- do {
816
- pq_node2dot(result_string, n1, level + 1);
817
- for (i=0; i<level; i++) rb_str_cat2(result_string, " ");
818
- rb_str_concat(result_string,
819
- rb_funcall(Qnil, id_format, 4, rb_str_new2("NODE%i -> NODE%i;\n"),
820
- ULONG2NUM((unsigned long) n), ULONG2NUM((unsigned long) n1)));
821
- n1 = n1->right;
822
- } while(n1 != n->child);
823
- }
824
- }
825
-
826
- /*
827
- * Print a priority queue as a dot-graph. The output can be fed to dot from the
828
- * vizgraph suite to create a tree depicting the internal datastructure.
829
- *
830
- * (I'm not proud of this function ;-( )
831
- */
832
- static
833
- VALUE pq_to_dot(VALUE self) {
834
- priority_queue* q = get_pq_from_value(self);
835
-
836
- VALUE result_string = rb_str_new2("digraph fibonacci_heap {\n");
837
- if (q->rootlist) {
838
- priority_node* n1 = q->rootlist;
839
- do {
840
- pq_node2dot(result_string, n1, 1);
841
- n1 = n1->right;
842
- } while(n1 != q->rootlist);
843
- }
844
- rb_str_cat2(result_string, "}\n");
845
- return result_string;
846
- }
847
-
848
- /*
849
- * Returns true if the array is empty, false otherwise.
850
- */
851
- static
852
- VALUE pq_empty(VALUE self) {
853
- priority_queue* q = get_pq_from_value(self);
854
- return priority_queue_empty(q) ? Qtrue : Qfalse;
855
- }
856
-
857
- static
858
- void pq_each_helper(priority_queue *q, priority_node *n, void *args) {
859
- rb_yield(rb_ary_new3(2, n->object, n->priority));
860
- };
861
-
862
- /*
863
- * Call the given block with each [key, priority] pair in the queue
864
- *
865
- * Beware: Changing the queue in the block may lead to unwanted behaviour and
866
- * even infinite loops.
867
- */
868
- static
869
- VALUE pq_each(VALUE self) {
870
- priority_queue* q = get_pq_from_value(self);
871
- priority_queue_each(q, &pq_each_helper, NULL);
872
- return self;
873
- }
874
-
875
- static
876
- VALUE pq_insert_node(VALUE node, VALUE queue) {
877
- return pq_push(queue, rb_ary_entry(node, 0), rb_ary_entry(node, 1));
878
- }
879
-
880
- static
881
- VALUE pq_initialize_copy(VALUE copy, VALUE orig) {
882
- if (copy == orig)
883
- return copy;
884
-
885
- rb_iterate(rb_each, orig, pq_insert_node, copy);
886
-
887
- return copy;
888
- }
889
-
890
- /*
891
- * Returns a string representation of the priority queue.
892
- */
893
- static
894
- VALUE pq_inspect(VALUE self) {
895
- VALUE result = rb_str_new2("<PriorityQueue: ");
896
- rb_str_concat(result,
897
- rb_funcall(rb_funcall(self, rb_intern("to_a"), 0),
898
- rb_intern("inspect"), 0));
899
- rb_str_concat(result, rb_str_new2(">"));
900
- return result;
901
- }
902
-
903
- static VALUE cPriorityQueue;
904
- static VALUE mContainers;
905
-
906
- /*
907
- * A Priority Queue implementation
908
- *
909
- * A priority queue is a queue, where each element (the key) has an assigned
910
- * priority. It is possible to efficently decrease priorities and to
911
- * efficently look up and remove the key with the smallest priority.
912
- *
913
- * This datastructure is used in different algorithms. The standard algorithm
914
- * used to introduce priority queues is dijkstra's shortest path algorithm.
915
- *
916
- * The priority queue includes the Enumerable module.
917
- */
918
- void Init_CPriorityQueue() {
919
- id_compare_operator = rb_intern("<=>");
920
- id_format = rb_intern("format");
921
- id_display = rb_intern("display");
922
-
923
- mContainers = rb_define_module("Containers");
924
- cPriorityQueue = rb_define_class_under(mContainers, "CPriorityQueue", rb_cObject);
925
-
926
- rb_define_alloc_func(cPriorityQueue, pq_alloc);
927
- rb_define_method(cPriorityQueue, "initialize", pq_init, 0);
928
- rb_define_method(cPriorityQueue, "initialize_copy", pq_initialize_copy, 1);
929
- rb_define_method(cPriorityQueue, "min", pq_min, 0);
930
- rb_define_method(cPriorityQueue, "min_key", pq_min_key, 0);
931
- rb_define_method(cPriorityQueue, "min_priority", pq_min_priority, 0);
932
- rb_define_method(cPriorityQueue, "delete_min", pq_delete_min, 0);
933
- rb_define_method(cPriorityQueue, "delete_min_return_key", pq_delete_min_return_key, 0);
934
- rb_define_method(cPriorityQueue, "delete_min_return_priority", pq_delete_min_return_priority, 0);
935
- rb_define_method(cPriorityQueue, "push", pq_change_priority, 2);
936
- rb_define_method(cPriorityQueue, "change_priority", pq_change_priority, 2);
937
- rb_define_method(cPriorityQueue, "[]=", pq_change_priority, 2);
938
- rb_define_method(cPriorityQueue, "priority", pq_get_priority, 1);
939
- rb_define_method(cPriorityQueue, "[]", pq_get_priority, 1);
940
- rb_define_method(cPriorityQueue, "has_key?", pq_has_key, 1);
941
- rb_define_method(cPriorityQueue, "length", pq_length, 0);
942
- rb_define_method(cPriorityQueue, "to_dot", pq_to_dot, 0);
943
- rb_define_method(cPriorityQueue, "empty?", pq_empty, 0);
944
- rb_define_method(cPriorityQueue, "delete", pq_delete, 1);
945
- rb_define_method(cPriorityQueue, "inspect", pq_inspect, 0);
946
- rb_define_method(cPriorityQueue, "each", pq_each, 0);
947
- rb_include_module(cPriorityQueue, rb_eval_string("Enumerable"));
948
- }