stakach-algorithms 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,71 +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
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
71
  end
@@ -1,72 +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
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
72
  end
@@ -1,188 +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
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
188
  end