stakach-algorithms 1.0.4 → 1.0.5

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.
@@ -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