algorithms 0.3.0-jruby

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/History.txt +172 -0
  2. data/Manifest +43 -0
  3. data/README.markdown +93 -0
  4. data/Rakefile +31 -0
  5. data/algorithms.gemspec +33 -0
  6. data/benchmarks/deque.rb +17 -0
  7. data/benchmarks/sorts.rb +34 -0
  8. data/benchmarks/treemaps.rb +51 -0
  9. data/ext/containers/deque/deque.c +247 -0
  10. data/ext/containers/deque/extconf.rb +4 -0
  11. data/ext/containers/rbtree_map/extconf.rb +4 -0
  12. data/ext/containers/rbtree_map/rbtree.c +498 -0
  13. data/ext/containers/splaytree_map/extconf.rb +4 -0
  14. data/ext/containers/splaytree_map/splaytree.c +419 -0
  15. data/lib/algorithms.rb +68 -0
  16. data/lib/algorithms/search.rb +84 -0
  17. data/lib/algorithms/sort.rb +238 -0
  18. data/lib/containers/deque.rb +171 -0
  19. data/lib/containers/heap.rb +486 -0
  20. data/lib/containers/kd_tree.rb +110 -0
  21. data/lib/containers/priority_queue.rb +113 -0
  22. data/lib/containers/queue.rb +68 -0
  23. data/lib/containers/rb_tree_map.rb +398 -0
  24. data/lib/containers/splay_tree_map.rb +269 -0
  25. data/lib/containers/stack.rb +67 -0
  26. data/lib/containers/suffix_array.rb +68 -0
  27. data/lib/containers/trie.rb +182 -0
  28. data/spec/deque_gc_mark_spec.rb +18 -0
  29. data/spec/deque_spec.rb +108 -0
  30. data/spec/heap_spec.rb +126 -0
  31. data/spec/kd_expected_out.txt +10000 -0
  32. data/spec/kd_test_in.txt +10000 -0
  33. data/spec/kd_tree_spec.rb +34 -0
  34. data/spec/map_gc_mark_spec.rb +27 -0
  35. data/spec/priority_queue_spec.rb +75 -0
  36. data/spec/queue_spec.rb +61 -0
  37. data/spec/rb_tree_map_spec.rb +123 -0
  38. data/spec/search_spec.rb +28 -0
  39. data/spec/sort_spec.rb +28 -0
  40. data/spec/splay_tree_map_spec.rb +106 -0
  41. data/spec/stack_spec.rb +60 -0
  42. data/spec/suffix_array_spec.rb +40 -0
  43. data/spec/trie_spec.rb +59 -0
  44. metadata +122 -0
@@ -0,0 +1,269 @@
1
+ require 'containers/stack'
2
+ =begin rdoc
3
+ A SplayTreeMap is a map that is stored in ascending order of its keys, determined by applying
4
+ the function <=> to compare keys. No duplicate values for keys are allowed, so new values of a key
5
+ overwrites the old value of the key.
6
+
7
+ A major advantage of SplayTreeMap over a Hash is the fact that keys are stored in order and can thus be
8
+ iterated over in order. Also, Splay Trees are self-optimizing as recently accessed nodes stay near
9
+ the root and are easily re-accessed later. Splay Trees are also more simply implemented than Red-Black
10
+ trees.
11
+
12
+ Splay trees have amortized O(log n) performance for most methods, but are O(n) worst case. This happens
13
+ when keys are added in sorted order, causing the tree to have a height of the number of items added.
14
+
15
+ =end
16
+ class Containers::RubySplayTreeMap
17
+ include Enumerable
18
+
19
+ Node = Struct.new(:key, :value, :left, :right)
20
+
21
+ # Create and initialize a new empty SplayTreeMap.
22
+ def initialize
23
+ @size = 0
24
+ clear
25
+ end
26
+
27
+ # Insert an item with an associated key into the SplayTreeMap, and returns the item inserted
28
+ #
29
+ # Complexity: amortized O(log n)
30
+ #
31
+ # map = Containers::SplayTreeMap.new
32
+ # map.push("MA", "Massachusetts") #=> "Massachusetts"
33
+ # map.get("MA") #=> "Massachusetts"
34
+ def push(key, value)
35
+ if @root.nil?
36
+ @root = Node.new(key, value, nil, nil)
37
+ @size = 1
38
+ return value
39
+ end
40
+ splay(key)
41
+
42
+ cmp = (key <=> @root.key)
43
+ if cmp == 0
44
+ @root.value = value
45
+ return value
46
+ end
47
+ node = Node.new(key, value, nil, nil)
48
+ if cmp < 1
49
+ node.left = @root.left
50
+ node.right = @root
51
+ @root.left = nil
52
+ else
53
+ node.right = @root.right
54
+ node.left = @root
55
+ @root.right = nil
56
+ end
57
+ @root = node
58
+ @size += 1
59
+ value
60
+ end
61
+ alias_method :[]=, :push
62
+
63
+ # Return the number of items in the SplayTreeMap.
64
+ #
65
+ # map = Containers::SplayTreeMap.new
66
+ # map.push("MA", "Massachusetts")
67
+ # map.push("GA", "Georgia")
68
+ # map.size #=> 2
69
+ def size
70
+ @size
71
+ end
72
+
73
+ # Remove all elements from the SplayTreeMap
74
+ #
75
+ # Complexity: O(1)
76
+ #
77
+ def clear
78
+ @root = nil
79
+ @size = 0
80
+ @header = Node.new(nil, nil, nil, nil)
81
+ end
82
+
83
+ # Return the height of the tree structure in the SplayTreeMap.
84
+ #
85
+ # Complexity: O(log n)
86
+ #
87
+ # map = Containers::SplayTreeMap.new
88
+ # map.push("MA", "Massachusetts")
89
+ # map.push("GA", "Georgia")
90
+ # map.height #=> 2
91
+ def height
92
+ height_recursive(@root)
93
+ end
94
+
95
+ # Return true if key is found in the SplayTreeMap, false otherwise.
96
+ #
97
+ # Complexity: amortized O(log n)
98
+ #
99
+ # map = Containers::SplayTreeMap.new
100
+ # map["MA"] = "Massachusetts"
101
+ # map["GA"] = "Georgia"
102
+ # map.has_key?("GA") #=> true
103
+ # map.has_key?("DE") #=> false
104
+ def has_key?(key)
105
+ !get(key).nil?
106
+ end
107
+
108
+ # Return the item associated with the key, or nil if none found.
109
+ #
110
+ # Complexity: amortized O(log n)
111
+ #
112
+ # map = Containers::SplayTreeMap.new
113
+ # map.push("MA", "Massachusetts")
114
+ # map.push("GA", "Georgia")
115
+ # map.get("GA") #=> "Georgia"
116
+ def get(key)
117
+ return nil if @root.nil?
118
+
119
+ splay(key)
120
+ (@root.key <=> key) == 0 ? @root.value : nil
121
+ end
122
+ alias_method :[], :get
123
+
124
+ # Return the smallest [key, value] pair in the SplayTreeMap, or nil if the tree is empty.
125
+ #
126
+ # Complexity: amortized O(log n)
127
+ #
128
+ # map = Containers::SplayTreeMap.new
129
+ # map["MA"] = "Massachusetts"
130
+ # map["GA"] = "Georgia"
131
+ # map.min #=> ["GA", "Georgia"]
132
+ def min
133
+ return nil if @root.nil?
134
+ n = @root
135
+ while n.left
136
+ n = n.left
137
+ end
138
+ splay(n.key)
139
+ return [n.key, n.value]
140
+ end
141
+
142
+ # Return the largest [key, value] pair in the SplayTreeMap, or nil if the tree is empty.
143
+ #
144
+ # Complexity: amortized O(log n)
145
+ #
146
+ # map = Containers::SplayTreeMap.new
147
+ # map["MA"] = "Massachusetts"
148
+ # map["GA"] = "Georgia"
149
+ # map.max #=> ["MA", "Massachusetts"]
150
+ def max
151
+ return nil if @root.nil?
152
+ n = @root
153
+ while n.right
154
+ n = n.right
155
+ end
156
+ splay(n.key)
157
+ return [n.key, n.value]
158
+ end
159
+
160
+ # Deletes the item and key if it's found, and returns the item. Returns nil
161
+ # if key is not present.
162
+ #
163
+ # Complexity: amortized O(log n)
164
+ #
165
+ # map = Containers::SplayTreeMap.new
166
+ # map["MA"] = "Massachusetts"
167
+ # map["GA"] = "Georgia"
168
+ # map.delete("GA") #=> "Georgia"
169
+ # map.delete("DE") #=> nil
170
+ def delete(key)
171
+ return nil if @root.nil?
172
+ deleted = nil
173
+ splay(key)
174
+ if (key <=> @root.key) == 0 # The key exists
175
+ deleted = @root.value
176
+ if @root.left.nil?
177
+ @root = @root.right
178
+ else
179
+ x = @root.right
180
+ @root = @root.left
181
+ splay(key)
182
+ @root.right = x
183
+ end
184
+ end
185
+ deleted
186
+ end
187
+
188
+ # Iterates over the SplayTreeMap in ascending order. Uses an iterative, not recursive, approach.
189
+ def each
190
+ return nil unless @root
191
+ stack = Containers::Stack.new
192
+ cursor = @root
193
+ loop do
194
+ if cursor
195
+ stack.push(cursor)
196
+ cursor = cursor.left
197
+ else
198
+ unless stack.empty?
199
+ cursor = stack.pop
200
+ yield(cursor.key, cursor.value)
201
+ cursor = cursor.right
202
+ else
203
+ break
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ # Moves a key to the root, updating the structure in each step.
210
+ def splay(key)
211
+ l, r = @header, @header
212
+ t = @root
213
+ @header.left, @header.right = nil, nil
214
+
215
+ loop do
216
+ if (key <=> t.key) == -1
217
+ break unless t.left
218
+ if (key <=> t.left.key) == -1
219
+ y = t.left
220
+ t.left = y.right
221
+ y.right = t
222
+ t = y
223
+ break unless t.left
224
+ end
225
+ r.left = t
226
+ r = t
227
+ t = t.left
228
+ elsif (key <=> t.key) == 1
229
+ break unless t.right
230
+ if (key <=> t.right.key) == 1
231
+ y = t.right
232
+ t.right = y.left
233
+ y.left = t
234
+ t = y
235
+ break unless t.right
236
+ end
237
+ l.right = t
238
+ l = t
239
+ t = t.right
240
+ else
241
+ break
242
+ end
243
+ end
244
+ l.right = t.left
245
+ r.left = t.right
246
+ t.left = @header.right
247
+ t.right = @header.left
248
+ @root = t
249
+ end
250
+ private :splay
251
+
252
+ # Recursively determine height
253
+ def height_recursive(node)
254
+ return 0 if node.nil?
255
+
256
+ left_height = 1 + height_recursive(node.left)
257
+ right_height = 1 + height_recursive(node.right)
258
+
259
+ left_height > right_height ? left_height : right_height
260
+ end
261
+ private :height_recursive
262
+ end
263
+
264
+ begin
265
+ require 'CSplayTreeMap'
266
+ Containers::SplayTreeMap = Containers::CSplayTreeMap
267
+ rescue LoadError # C Version could not be found, try ruby version
268
+ Containers::SplayTreeMap = Containers::RubySplayTreeMap
269
+ end
@@ -0,0 +1,67 @@
1
+ require 'containers/deque'
2
+ =begin rdoc
3
+ A Stack is a container that keeps elements in a last-in first-out (LIFO) order. There are many
4
+ uses for stacks, including prefix-infix-postfix conversion and backtracking problems.
5
+
6
+ This implementation uses a doubly-linked list, guaranteeing O(1) complexity for all operations.
7
+
8
+ =end
9
+ class Containers::Stack
10
+ include Enumerable
11
+ # Create a new stack. Takes an optional array argument to initialize the stack.
12
+ #
13
+ # s = Containers::Stack.new([1, 2, 3])
14
+ # s.pop #=> 3
15
+ # s.pop #=> 2
16
+ def initialize(ary=[])
17
+ @container = Containers::Deque.new(ary)
18
+ end
19
+
20
+ # Returns the next item from the stack but does not remove it.
21
+ #
22
+ # s = Containers::Stack.new([1, 2, 3])
23
+ # s.next #=> 3
24
+ # s.size #=> 3
25
+ def next
26
+ @container.back
27
+ end
28
+
29
+ # Adds an item to the stack.
30
+ #
31
+ # s = Containers::Stack.new([1])
32
+ # s.push(2)
33
+ # s.pop #=> 2
34
+ # s.pop #=> 1
35
+ def push(obj)
36
+ @container.push_back(obj)
37
+ end
38
+ alias_method :<<, :push
39
+
40
+ # Removes the next item from the stack and returns it.
41
+ #
42
+ # s = Containers::Stack.new([1, 2, 3])
43
+ # s.pop #=> 3
44
+ # s.size #=> 2
45
+ def pop
46
+ @container.pop_back
47
+ end
48
+
49
+ # Return the number of items in the stack.
50
+ #
51
+ # s = Containers::Stack.new([1, 2, 3])
52
+ # s.size #=> 3
53
+ def size
54
+ @container.size
55
+ end
56
+
57
+ # Returns true if the stack is empty, false otherwise.
58
+ def empty?
59
+ @container.empty?
60
+ end
61
+
62
+ # Iterate over the Stack in LIFO order.
63
+ def each(&block)
64
+ @container.each_backward(&block)
65
+ end
66
+
67
+ end
@@ -0,0 +1,68 @@
1
+ =begin rdoc
2
+ A suffix array enables fast substring search of a given string. An array of all possible substrings
3
+ is constructed and stored, and a binary search is then done to find a desired substring among those
4
+ stored. While more storage (and thus memory) is needed to create the SuffixArray, the advantage is
5
+ that substrings can be found in O(m log n) time, where m is the length of the substring to search for
6
+ and n is the total number of substrings.
7
+
8
+ =end
9
+ class Containers::SuffixArray
10
+ # Creates a new SuffixArray with a given string. Object of any class implementing a #to_s method can
11
+ # be passed in, such as integers.
12
+ #
13
+ # Complexity: O(n^2 log n)
14
+ #
15
+ # s_array = Containers::SuffixArray("abracadabra")
16
+ # s_array["abra"] #=> true
17
+ #
18
+ # number = Containers::SuffixArray(1234567)
19
+ # number[1] #=> true
20
+ # number[13] #=> false
21
+ def initialize(string)
22
+ string = string.to_s
23
+ raise ArgumentError, "SuffixArray needs to be initialized with a non-empty string" if string.empty?
24
+ @original_string = string
25
+ @suffixes = []
26
+ string.length.times do |i|
27
+ @suffixes << string[i..-1]
28
+ end
29
+
30
+ # Sort the suffixes in ascending order
31
+ @suffixes.sort! { |x, y| x <=> y }
32
+ end
33
+
34
+ # Returns true if the substring occurs in the string, false otherwise.
35
+ #
36
+ # Complexity: O(m + log n)
37
+ #
38
+ # s_array = Containers::SuffixArray.new("abracadabra")
39
+ # s_array.has_substring?("a") #=> true
40
+ # s_array.has_substring?("abra") #=> true
41
+ # s_array.has_substring?("abracadabra") #=> true
42
+ # s_array.has_substring?("acadabra") #=> true
43
+ # s_array.has_substring?("adabra") #=> true
44
+ # s_array.has_substring?("bra") #=> true
45
+ # s_array.has_substring?("bracadabra") #=> true
46
+ # s_array.has_substring?("cadabra") #=> true
47
+ # s_array.has_substring?("dabra") #=> true
48
+ # s_array.has_substring?("ra") #=> true
49
+ # s_array.has_substring?("racadabra") #=> true
50
+ # s_array.has_substring?("nope") #=> false
51
+ def has_substring?(substring)
52
+ substring = substring.to_s
53
+ return false if substring.empty?
54
+ substring_length = substring.length-1
55
+ l, r = 0, @suffixes.size-1
56
+ while(l <= r)
57
+ mid = (l + r) / 2
58
+ suffix = @suffixes[mid][0..substring_length]
59
+ case substring <=> suffix
60
+ when 0 then return true
61
+ when 1 then l = mid + 1
62
+ when -1 then r = mid - 1
63
+ end
64
+ end
65
+ return false
66
+ end
67
+ alias_method :[], :has_substring?
68
+ end
@@ -0,0 +1,182 @@
1
+ =begin rdoc
2
+ A Trie is a data structure that stores key value pairs in a tree-like fashion. It allows
3
+ O(m) lookup speed, where m is the length of the key searched, and has no chance of collisions,
4
+ unlike hash tables. Because of its nature, search misses are quickly detected.
5
+
6
+ Tries are often used for longest prefix algorithms, wildcard matching, and can be used to
7
+ implement a radix sort.
8
+
9
+ This implemention is based on a Ternary Search Tree.
10
+ =end
11
+ class Containers::Trie
12
+ # Create a new, empty Trie.
13
+ #
14
+ # t = Containers::Trie.new
15
+ # t["hello"] = "world"
16
+ # t["hello] #=> "world"
17
+ def initialize
18
+ @root = nil
19
+ end
20
+
21
+ # Adds a key, value pair to the Trie, and returns the value if successful. The to_s method is
22
+ # called on the parameter to turn it into a string.
23
+ #
24
+ # Complexity: O(m)
25
+ #
26
+ # t = Containers::Trie.new
27
+ # t["hello"] = "world"
28
+ # t.push("hello", "world") # does the same thing
29
+ # t["hello"] #=> "world"
30
+ # t[1] = 1
31
+ # t[1] #=> 1
32
+ def push(key, value)
33
+ key = key.to_s
34
+ return nil if key.empty?
35
+ @root = push_recursive(@root, key, 0, value)
36
+ value
37
+ end
38
+ alias_method :[]=, :push
39
+
40
+ # Returns true if the key is contained in the Trie.
41
+ #
42
+ # Complexity: O(m) worst case
43
+ #
44
+ def has_key?(key)
45
+ key = key.to_s
46
+ return false if key.empty?
47
+ !(get_recursive(@root, key, 0).nil?)
48
+ end
49
+
50
+ # Returns the value of the desired key, or nil if the key doesn't exist.
51
+ #
52
+ # Complexity: O(m) worst case
53
+ #
54
+ # t = Containers::Trie.new
55
+ # t.get("hello") = "world"
56
+ # t.get("non-existant") #=> nil
57
+ def get(key)
58
+ key = key.to_s
59
+ return nil if key.empty?
60
+ node = get_recursive(@root, key, 0)
61
+ node ? node.last : nil
62
+ end
63
+ alias_method :[], :get
64
+
65
+ # Returns the longest key that has a prefix in common with the parameter string. If
66
+ # no match is found, the blank string "" is returned.
67
+ #
68
+ # Complexity: O(m) worst case
69
+ #
70
+ # t = Containers::Trie.new
71
+ # t.push("Hello", "World")
72
+ # t.push("Hello, brother", "World")
73
+ # t.push("Hello, bob", "World")
74
+ # t.longest_prefix("Hello, brandon") #=> "Hello"
75
+ # t.longest_prefix("Hel") #=> ""
76
+ # t.longest_prefix("Hello") #=> "Hello"
77
+ def longest_prefix(string)
78
+ string = string.to_s
79
+ return nil if string.empty?
80
+ len = prefix_recursive(@root, string, 0)
81
+ string[0...len]
82
+ end
83
+
84
+ # Returns a sorted array containing strings that match the parameter string. The wildcard
85
+ # characters that match any character are '*' and '.' If no match is found, an empty
86
+ # array is returned.
87
+ #
88
+ # Complexity: O(n) worst case
89
+ #
90
+ # t = Containers::Trie.new
91
+ # t.push("Hello", "World")
92
+ # t.push("Hilly", "World")
93
+ # t.push("Hello, bob", "World")
94
+ # t.wildcard("H*ll.") #=> ["Hello", "Hilly"]
95
+ # t.wildcard("Hel") #=> []
96
+ def wildcard(string)
97
+ string = string.to_s
98
+ return nil if string.empty?
99
+ ary = []
100
+ ary << wildcard_recursive(@root, string, 0, "")
101
+ ary.flatten.compact.sort
102
+ end
103
+
104
+ class Node # :nodoc: all
105
+ attr_accessor :left, :mid, :right, :char, :value, :end
106
+
107
+ def initialize(char, value)
108
+ @char = char
109
+ @value = value
110
+ @left = @mid = @right = nil
111
+ @end = false
112
+ end
113
+
114
+ def last?
115
+ @end == true
116
+ end
117
+ end
118
+
119
+ def wildcard_recursive(node, string, index, prefix)
120
+ return nil if node.nil? || index == string.length
121
+ arr = []
122
+ char = string[index]
123
+ if (char.chr == "*" || char.chr == "." || char < node.char)
124
+ arr << wildcard_recursive(node.left, string, index, prefix)
125
+ end
126
+ if (char.chr == "*" || char.chr == "." || char > node.char)
127
+ arr << wildcard_recursive(node.right, string, index, prefix)
128
+ end
129
+ if (char.chr == "*" || char.chr == "." || char == node.char)
130
+ arr << "#{prefix}#{node.char.chr}" if node.last?
131
+ arr << wildcard_recursive(node.mid, string, index+1, prefix + node.char.chr)
132
+ end
133
+ arr
134
+ end
135
+
136
+ def prefix_recursive(node, string, index)
137
+ return 0 if node.nil? || index == string.length
138
+ len = 0
139
+ rec_len = 0
140
+ char = string[index]
141
+ if (char < node.char)
142
+ rec_len = prefix_recursive(node.left, string, index)
143
+ elsif (char > node.char)
144
+ rec_len = prefix_recursive(node.right, string, index)
145
+ else
146
+ len = index+1 if node.last?
147
+ rec_len = prefix_recursive(node.mid, string, index+1)
148
+ end
149
+ len > rec_len ? len : rec_len
150
+ end
151
+
152
+ def push_recursive(node, string, index, value)
153
+ char = string[index]
154
+ node = Node.new(char, value) if node.nil?
155
+ if (char < node.char)
156
+ node.left = push_recursive(node.left, string, index, value)
157
+ elsif (char > node.char)
158
+ node.right = push_recursive(node.right, string, index, value)
159
+ elsif (index < string.length-1) # We're not at the end of the input string; add next char
160
+ node.mid = push_recursive(node.mid, string, index+1, value)
161
+ else
162
+ node.end = true
163
+ node.value = value
164
+ end
165
+ node
166
+ end
167
+
168
+ # Returns [char, value] if found
169
+ def get_recursive(node, string, index)
170
+ return nil if node.nil?
171
+ char = string[index]
172
+ if (char < node.char)
173
+ return get_recursive(node.left, string, index)
174
+ elsif (char > node.char)
175
+ return get_recursive(node.right, string, index)
176
+ elsif (index < string.length-1) # We're not at the end of the input string; add next char
177
+ return get_recursive(node.mid, string, index+1)
178
+ else
179
+ return node.last? ? [node.char, node.value] : nil
180
+ end
181
+ end
182
+ end