grosser-algorithms 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/History.txt +176 -0
  2. data/Manifest +47 -0
  3. data/README.markdown +102 -0
  4. data/Rakefile +26 -0
  5. data/algorithms.gemspec +32 -0
  6. data/benchmarks/deque.rb +18 -0
  7. data/benchmarks/sorts.rb +34 -0
  8. data/benchmarks/treemaps.rb +52 -0
  9. data/ext/algorithms/string/extconf.rb +4 -0
  10. data/ext/algorithms/string/string.c +70 -0
  11. data/ext/containers/deque/deque.c +249 -0
  12. data/ext/containers/deque/extconf.rb +4 -0
  13. data/ext/containers/rbtree_map/extconf.rb +4 -0
  14. data/ext/containers/rbtree_map/rbtree.c +500 -0
  15. data/ext/containers/splaytree_map/extconf.rb +4 -0
  16. data/ext/containers/splaytree_map/splaytree.c +421 -0
  17. data/grosser-algorithms.gemspec +31 -0
  18. data/lib/algorithms.rb +71 -0
  19. data/lib/algorithms/search.rb +86 -0
  20. data/lib/algorithms/sort.rb +243 -0
  21. data/lib/algorithms/string.rb +8 -0
  22. data/lib/containers/deque.rb +176 -0
  23. data/lib/containers/heap.rb +507 -0
  24. data/lib/containers/kd_tree.rb +113 -0
  25. data/lib/containers/priority_queue.rb +117 -0
  26. data/lib/containers/queue.rb +72 -0
  27. data/lib/containers/rb_tree_map.rb +402 -0
  28. data/lib/containers/splay_tree_map.rb +273 -0
  29. data/lib/containers/stack.rb +71 -0
  30. data/lib/containers/suffix_array.rb +72 -0
  31. data/lib/containers/trie.rb +188 -0
  32. data/spec/deque_gc_mark_spec.rb +18 -0
  33. data/spec/deque_spec.rb +108 -0
  34. data/spec/heap_spec.rb +126 -0
  35. data/spec/kd_expected_out.txt +10000 -0
  36. data/spec/kd_test_in.txt +10000 -0
  37. data/spec/kd_tree_spec.rb +34 -0
  38. data/spec/map_gc_mark_spec.rb +29 -0
  39. data/spec/priority_queue_spec.rb +75 -0
  40. data/spec/queue_spec.rb +61 -0
  41. data/spec/rb_tree_map_spec.rb +122 -0
  42. data/spec/search_spec.rb +28 -0
  43. data/spec/sort_spec.rb +27 -0
  44. data/spec/splay_tree_map_spec.rb +106 -0
  45. data/spec/stack_spec.rb +60 -0
  46. data/spec/string_spec.rb +13 -0
  47. data/spec/suffix_array_spec.rb +40 -0
  48. data/spec/trie_spec.rb +59 -0
  49. metadata +141 -0
@@ -0,0 +1,273 @@
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
+ module Algorithms
17
+ module Containers
18
+ class RubySplayTreeMap
19
+ include Enumerable
20
+
21
+ Node = Struct.new(:key, :value, :left, :right)
22
+
23
+ # Create and initialize a new empty SplayTreeMap.
24
+ def initialize
25
+ @size = 0
26
+ clear
27
+ end
28
+
29
+ # Insert an item with an associated key into the SplayTreeMap, and returns the item inserted
30
+ #
31
+ # Complexity: amortized O(log n)
32
+ #
33
+ # map = Algorithms::Containers::SplayTreeMap.new
34
+ # map.push("MA", "Massachusetts") #=> "Massachusetts"
35
+ # map.get("MA") #=> "Massachusetts"
36
+ def push(key, value)
37
+ if @root.nil?
38
+ @root = Node.new(key, value, nil, nil)
39
+ @size = 1
40
+ return value
41
+ end
42
+ splay(key)
43
+
44
+ cmp = (key <=> @root.key)
45
+ if cmp == 0
46
+ @root.value = value
47
+ return value
48
+ end
49
+ node = Node.new(key, value, nil, nil)
50
+ if cmp < 1
51
+ node.left = @root.left
52
+ node.right = @root
53
+ @root.left = nil
54
+ else
55
+ node.right = @root.right
56
+ node.left = @root
57
+ @root.right = nil
58
+ end
59
+ @root = node
60
+ @size += 1
61
+ value
62
+ end
63
+ alias_method :[]=, :push
64
+
65
+ # Return the number of items in the SplayTreeMap.
66
+ #
67
+ # map = Algorithms::Containers::SplayTreeMap.new
68
+ # map.push("MA", "Massachusetts")
69
+ # map.push("GA", "Georgia")
70
+ # map.size #=> 2
71
+ def size
72
+ @size
73
+ end
74
+
75
+ # Remove all elements from the SplayTreeMap
76
+ #
77
+ # Complexity: O(1)
78
+ #
79
+ def clear
80
+ @root = nil
81
+ @size = 0
82
+ @header = Node.new(nil, nil, nil, nil)
83
+ end
84
+
85
+ # Return the height of the tree structure in the SplayTreeMap.
86
+ #
87
+ # Complexity: O(log n)
88
+ #
89
+ # map = Algorithms::Containers::SplayTreeMap.new
90
+ # map.push("MA", "Massachusetts")
91
+ # map.push("GA", "Georgia")
92
+ # map.height #=> 2
93
+ def height
94
+ height_recursive(@root)
95
+ end
96
+
97
+ # Return true if key is found in the SplayTreeMap, false otherwise.
98
+ #
99
+ # Complexity: amortized O(log n)
100
+ #
101
+ # map = Algorithms::Containers::SplayTreeMap.new
102
+ # map["MA"] = "Massachusetts"
103
+ # map["GA"] = "Georgia"
104
+ # map.has_key?("GA") #=> true
105
+ # map.has_key?("DE") #=> false
106
+ def has_key?(key)
107
+ !get(key).nil?
108
+ end
109
+
110
+ # Return the item associated with the key, or nil if none found.
111
+ #
112
+ # Complexity: amortized O(log n)
113
+ #
114
+ # map = Algorithms::Containers::SplayTreeMap.new
115
+ # map.push("MA", "Massachusetts")
116
+ # map.push("GA", "Georgia")
117
+ # map.get("GA") #=> "Georgia"
118
+ def get(key)
119
+ return nil if @root.nil?
120
+
121
+ splay(key)
122
+ (@root.key <=> key) == 0 ? @root.value : nil
123
+ end
124
+ alias_method :[], :get
125
+
126
+ # Return the smallest [key, value] pair in the SplayTreeMap, or nil if the tree is empty.
127
+ #
128
+ # Complexity: amortized O(log n)
129
+ #
130
+ # map = Algorithms::Containers::SplayTreeMap.new
131
+ # map["MA"] = "Massachusetts"
132
+ # map["GA"] = "Georgia"
133
+ # map.min #=> ["GA", "Georgia"]
134
+ def min
135
+ return nil if @root.nil?
136
+ n = @root
137
+ while n.left
138
+ n = n.left
139
+ end
140
+ splay(n.key)
141
+ return [n.key, n.value]
142
+ end
143
+
144
+ # Return the largest [key, value] pair in the SplayTreeMap, or nil if the tree is empty.
145
+ #
146
+ # Complexity: amortized O(log n)
147
+ #
148
+ # map = Algorithms::Containers::SplayTreeMap.new
149
+ # map["MA"] = "Massachusetts"
150
+ # map["GA"] = "Georgia"
151
+ # map.max #=> ["MA", "Massachusetts"]
152
+ def max
153
+ return nil if @root.nil?
154
+ n = @root
155
+ while n.right
156
+ n = n.right
157
+ end
158
+ splay(n.key)
159
+ return [n.key, n.value]
160
+ end
161
+
162
+ # Deletes the item and key if it's found, and returns the item. Returns nil
163
+ # if key is not present.
164
+ #
165
+ # Complexity: amortized O(log n)
166
+ #
167
+ # map = Algorithms::Containers::SplayTreeMap.new
168
+ # map["MA"] = "Massachusetts"
169
+ # map["GA"] = "Georgia"
170
+ # map.delete("GA") #=> "Georgia"
171
+ # map.delete("DE") #=> nil
172
+ def delete(key)
173
+ return nil if @root.nil?
174
+ deleted = nil
175
+ splay(key)
176
+ if (key <=> @root.key) == 0 # The key exists
177
+ deleted = @root.value
178
+ if @root.left.nil?
179
+ @root = @root.right
180
+ else
181
+ x = @root.right
182
+ @root = @root.left
183
+ splay(key)
184
+ @root.right = x
185
+ end
186
+ end
187
+ deleted
188
+ end
189
+
190
+ # Iterates over the SplayTreeMap in ascending order. Uses an iterative, not recursive, approach.
191
+ def each
192
+ return nil unless @root
193
+ stack = Stack.new
194
+ cursor = @root
195
+ loop do
196
+ if cursor
197
+ stack.push(cursor)
198
+ cursor = cursor.left
199
+ else
200
+ unless stack.empty?
201
+ cursor = stack.pop
202
+ yield(cursor.key, cursor.value)
203
+ cursor = cursor.right
204
+ else
205
+ break
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ # Moves a key to the root, updating the structure in each step.
212
+ def splay(key)
213
+ l, r = @header, @header
214
+ t = @root
215
+ @header.left, @header.right = nil, nil
216
+
217
+ loop do
218
+ if (key <=> t.key) == -1
219
+ break unless t.left
220
+ if (key <=> t.left.key) == -1
221
+ y = t.left
222
+ t.left = y.right
223
+ y.right = t
224
+ t = y
225
+ break unless t.left
226
+ end
227
+ r.left = t
228
+ r = t
229
+ t = t.left
230
+ elsif (key <=> t.key) == 1
231
+ break unless t.right
232
+ if (key <=> t.right.key) == 1
233
+ y = t.right
234
+ t.right = y.left
235
+ y.left = t
236
+ t = y
237
+ break unless t.right
238
+ end
239
+ l.right = t
240
+ l = t
241
+ t = t.right
242
+ else
243
+ break
244
+ end
245
+ end
246
+ l.right = t.left
247
+ r.left = t.right
248
+ t.left = @header.right
249
+ t.right = @header.left
250
+ @root = t
251
+ end
252
+ private :splay
253
+
254
+ # Recursively determine height
255
+ def height_recursive(node)
256
+ return 0 if node.nil?
257
+
258
+ left_height = 1 + height_recursive(node.left)
259
+ right_height = 1 + height_recursive(node.right)
260
+
261
+ left_height > right_height ? left_height : right_height
262
+ end
263
+ private :height_recursive
264
+ end
265
+ end
266
+
267
+ begin
268
+ require 'CSplayTreeMap'
269
+ Containers::SplayTreeMap = Containers::CSplayTreeMap
270
+ rescue LoadError # C Version could not be found, try ruby version
271
+ Containers::SplayTreeMap = Containers::RubySplayTreeMap
272
+ end
273
+ end
@@ -0,0 +1,71 @@
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
+ module Algorithms
10
+ module Containers
11
+ class Stack
12
+ include Enumerable
13
+ # Create a new stack. Takes an optional array argument to initialize the stack.
14
+ #
15
+ # s = Algorithms::Containers::Stack.new([1, 2, 3])
16
+ # s.pop #=> 3
17
+ # s.pop #=> 2
18
+ def initialize(ary=[])
19
+ @container = Deque.new(ary)
20
+ end
21
+
22
+ # Returns the next item from the stack but does not remove it.
23
+ #
24
+ # s = Algorithms::Containers::Stack.new([1, 2, 3])
25
+ # s.next #=> 3
26
+ # s.size #=> 3
27
+ def next
28
+ @container.back
29
+ end
30
+
31
+ # Adds an item to the stack.
32
+ #
33
+ # s = Algorithms::Containers::Stack.new([1])
34
+ # s.push(2)
35
+ # s.pop #=> 2
36
+ # s.pop #=> 1
37
+ def push(obj)
38
+ @container.push_back(obj)
39
+ end
40
+ alias_method :<<, :push
41
+
42
+ # Removes the next item from the stack and returns it.
43
+ #
44
+ # s = Algorithms::Containers::Stack.new([1, 2, 3])
45
+ # s.pop #=> 3
46
+ # s.size #=> 2
47
+ def pop
48
+ @container.pop_back
49
+ end
50
+
51
+ # Return the number of items in the stack.
52
+ #
53
+ # s = Algorithms::Containers::Stack.new([1, 2, 3])
54
+ # s.size #=> 3
55
+ def size
56
+ @container.size
57
+ end
58
+
59
+ # Returns true if the stack is empty, false otherwise.
60
+ def empty?
61
+ @container.empty?
62
+ end
63
+
64
+ # Iterate over the Stack in LIFO order.
65
+ def each(&block)
66
+ @container.each_backward(&block)
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,72 @@
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
+ module Algorithms
10
+ module Containers
11
+ class SuffixArray
12
+ # Creates a new SuffixArray with a given string. Object of any class implementing a #to_s method can
13
+ # be passed in, such as integers.
14
+ #
15
+ # Complexity: O(n^2 log n)
16
+ #
17
+ # s_array = Algorithms::Containers::SuffixArray.new("abracadabra")
18
+ # s_array["abra"] #=> true
19
+ #
20
+ # number = Algorithms::Containers::SuffixArray.new(1234567)
21
+ # number[1] #=> true
22
+ # number[13] #=> false
23
+ def initialize(string)
24
+ string = string.to_s
25
+ raise ArgumentError, "SuffixArray needs to be initialized with a non-empty string" if string.empty?
26
+ @original_string = string
27
+ @suffixes = []
28
+ string.length.times do |i|
29
+ @suffixes << string[i..-1]
30
+ end
31
+
32
+ # Sort the suffixes in ascending order
33
+ @suffixes.sort! { |x, y| x <=> y }
34
+ end
35
+
36
+ # Returns true if the substring occurs in the string, false otherwise.
37
+ #
38
+ # Complexity: O(m + log n)
39
+ #
40
+ # s_array = Algorithms::Containers::SuffixArray.new("abracadabra")
41
+ # s_array.has_substring?("a") #=> true
42
+ # s_array.has_substring?("abra") #=> true
43
+ # s_array.has_substring?("abracadabra") #=> true
44
+ # s_array.has_substring?("acadabra") #=> true
45
+ # s_array.has_substring?("adabra") #=> true
46
+ # s_array.has_substring?("bra") #=> true
47
+ # s_array.has_substring?("bracadabra") #=> true
48
+ # s_array.has_substring?("cadabra") #=> true
49
+ # s_array.has_substring?("dabra") #=> true
50
+ # s_array.has_substring?("ra") #=> true
51
+ # s_array.has_substring?("racadabra") #=> true
52
+ # s_array.has_substring?("nope") #=> false
53
+ def has_substring?(substring)
54
+ substring = substring.to_s
55
+ return false if substring.empty?
56
+ substring_length = substring.length-1
57
+ l, r = 0, @suffixes.size-1
58
+ while(l <= r)
59
+ mid = (l + r) / 2
60
+ suffix = @suffixes[mid][0..substring_length]
61
+ case substring <=> suffix
62
+ when 0 then return true
63
+ when 1 then l = mid + 1
64
+ when -1 then r = mid - 1
65
+ end
66
+ end
67
+ return false
68
+ end
69
+ alias_method :[], :has_substring?
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,188 @@
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
+ module Algorithms
12
+ module Containers
13
+ class Trie
14
+ # Create a new, empty Trie.
15
+ #
16
+ # t =
17
+ # Trie.new
18
+ # t["hello"] = "world"
19
+ # t["hello] #=> "world"
20
+ def initialize
21
+ @root = nil
22
+ end
23
+
24
+ # Adds a key, value pair to the Trie, and returns the value if successful. The to_s method is
25
+ # called on the parameter to turn it into a string.
26
+ #
27
+ # Complexity: O(m)
28
+ #
29
+ # t = Algorithms::Containers::Trie.new
30
+ # t["hello"] = "world"
31
+ # t.push("hello", "world") # does the same thing
32
+ # t["hello"] #=> "world"
33
+ # t[1] = 1
34
+ # t[1] #=> 1
35
+ def push(key, value)
36
+ key = key.to_s
37
+ return nil if key.empty?
38
+ @root = push_recursive(@root, key, 0, value)
39
+ value
40
+ end
41
+ alias_method :[]=, :push
42
+
43
+ # Returns true if the key is contained in the Trie.
44
+ #
45
+ # Complexity: O(m) worst case
46
+ #
47
+ def has_key?(key)
48
+ key = key.to_s
49
+ return false if key.empty?
50
+ !(get_recursive(@root, key, 0).nil?)
51
+ end
52
+ alias_method :include?, :has_key?
53
+
54
+ # Returns the value of the desired key, or nil if the key doesn't exist.
55
+ #
56
+ # Complexity: O(m) worst case
57
+ #
58
+ # t = Algorithms::Containers::Trie.new
59
+ # t.get("hello") = "world"
60
+ # t.get("non-existant") #=> nil
61
+ def get(key)
62
+ key = key.to_s
63
+ return nil if key.empty?
64
+ node = get_recursive(@root, key, 0)
65
+ node ? node.last : nil
66
+ end
67
+ alias_method :[], :get
68
+
69
+ # Returns the longest key that has a prefix in common with the parameter string. If
70
+ # no match is found, the blank string "" is returned.
71
+ #
72
+ # Complexity: O(m) worst case
73
+ #
74
+ # t = Algorithms::Containers::Trie.new
75
+ # t.push("Hello", "World")
76
+ # t.push("Hello, brother", "World")
77
+ # t.push("Hello, bob", "World")
78
+ # t.longest_prefix("Hello, brandon") #=> "Hello"
79
+ # t.longest_prefix("Hel") #=> ""
80
+ # t.longest_prefix("Hello") #=> "Hello"
81
+ def longest_prefix(string)
82
+ string = string.to_s
83
+ return nil if string.empty?
84
+ len = prefix_recursive(@root, string, 0)
85
+ string[0...len]
86
+ end
87
+
88
+ # Returns a sorted array containing strings that match the parameter string. The wildcard
89
+ # characters that match any character are '*' and '.' If no match is found, an empty
90
+ # array is returned.
91
+ #
92
+ # Complexity: O(n) worst case
93
+ #
94
+ # t = Algorithms::Containers::Trie.new
95
+ # t.push("Hello", "World")
96
+ # t.push("Hilly", "World")
97
+ # t.push("Hello, bob", "World")
98
+ # t.wildcard("H*ll.") #=> ["Hello", "Hilly"]
99
+ # t.wildcard("Hel") #=> []
100
+ def wildcard(string)
101
+ string = string.to_s
102
+ return nil if string.empty?
103
+ ary = []
104
+ ary << wildcard_recursive(@root, string, 0, "")
105
+ ary.flatten.compact.sort
106
+ end
107
+
108
+ class Node # :nodoc: all
109
+ attr_accessor :left, :mid, :right, :char, :value, :end
110
+
111
+ def initialize(char, value)
112
+ @char = char
113
+ @value = value
114
+ @left = @mid = @right = nil
115
+ @end = false
116
+ end
117
+
118
+ def last?
119
+ @end == true
120
+ end
121
+ end
122
+
123
+ def wildcard_recursive(node, string, index, prefix)
124
+ return nil if node.nil? || index == string.length
125
+ arr = []
126
+ char = string[index]
127
+ if (char.chr == "*" || char.chr == "." || char < node.char)
128
+ arr << wildcard_recursive(node.left, string, index, prefix)
129
+ end
130
+ if (char.chr == "*" || char.chr == "." || char > node.char)
131
+ arr << wildcard_recursive(node.right, string, index, prefix)
132
+ end
133
+ if (char.chr == "*" || char.chr == "." || char == node.char)
134
+ arr << "#{prefix}#{node.char.chr}" if node.last?
135
+ arr << wildcard_recursive(node.mid, string, index+1, prefix + node.char.chr)
136
+ end
137
+ arr
138
+ end
139
+
140
+ def prefix_recursive(node, string, index)
141
+ return 0 if node.nil? || index == string.length
142
+ len = 0
143
+ rec_len = 0
144
+ char = string[index]
145
+ if (char < node.char)
146
+ rec_len = prefix_recursive(node.left, string, index)
147
+ elsif (char > node.char)
148
+ rec_len = prefix_recursive(node.right, string, index)
149
+ else
150
+ len = index+1 if node.last?
151
+ rec_len = prefix_recursive(node.mid, string, index+1)
152
+ end
153
+ len > rec_len ? len : rec_len
154
+ end
155
+
156
+ def push_recursive(node, string, index, value)
157
+ char = string[index]
158
+ node = Node.new(char, value) if node.nil?
159
+ if (char < node.char)
160
+ node.left = push_recursive(node.left, string, index, value)
161
+ elsif (char > node.char)
162
+ node.right = push_recursive(node.right, string, index, value)
163
+ elsif (index < string.length-1) # We're not at the end of the input string; add next char
164
+ node.mid = push_recursive(node.mid, string, index+1, value)
165
+ else
166
+ node.end = true
167
+ node.value = value
168
+ end
169
+ node
170
+ end
171
+
172
+ # Returns [char, value] if found
173
+ def get_recursive(node, string, index)
174
+ return nil if node.nil?
175
+ char = string[index]
176
+ if (char < node.char)
177
+ return get_recursive(node.left, string, index)
178
+ elsif (char > node.char)
179
+ return get_recursive(node.right, string, index)
180
+ elsif (index < string.length-1) # We're not at the end of the input string; add next char
181
+ return get_recursive(node.mid, string, index+1)
182
+ else
183
+ return node.last? ? [node.char, node.value] : nil
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end