trie 0.0.1

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 (9) hide show
  1. data/COPYING +340 -0
  2. data/INSTALL +232 -0
  3. data/MANIFEST +8 -0
  4. data/README +6 -0
  5. data/lib/trie.rb +422 -0
  6. data/setup.rb +1551 -0
  7. data/test/tests.rb +257 -0
  8. data/trie.gemspec +16 -0
  9. metadata +49 -0
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/ruby -w
2
+ #
3
+ # = Name
4
+ # TestTrie
5
+ #
6
+ # == Description
7
+ # This file contains unit tests for the Trie class.
8
+ #
9
+ # == Author
10
+ # Daniel Erat <dan-ruby@erat.org>
11
+ #
12
+ # == Copyright
13
+ # Copyright 2005 Daniel Erat
14
+ #
15
+ # == License
16
+ # GNU GPL; see COPYING
17
+
18
+ require 'test/unit'
19
+ require 'trie'
20
+
21
+ # Unit tests for the Trie class.
22
+ class TestTrie < Test::Unit::TestCase
23
+ # Test a compressed key with a single value at the root.
24
+ def test_find_compressed_key_single_value_at_root
25
+ t = Trie.new.insert('abc', 1)
26
+ assert_equal(t.find('abc').values, [1])
27
+ assert_equal(t.find('abc').find('').values, [1])
28
+ assert_equal(t.find('a').values, [])
29
+ assert_equal(t.find('').values, [])
30
+ assert_equal(t.find('b').values, [])
31
+ assert_equal(t.find_prefix('abc').values, [1])
32
+ assert_equal(t.find_prefix('abc').find_prefix('').values, [1])
33
+ assert_equal(t.find_prefix('ab').values, [1])
34
+ assert_equal(t.find_prefix('a').values, [1])
35
+ assert_equal(t.find_prefix('').values, [1])
36
+ assert_equal(t.find_prefix('b').values, [])
37
+ end
38
+
39
+ # Test a compressed key with multiple values at the root.
40
+ def test_find_compressed_key_multiple_values_at_root
41
+ t = Trie.new.insert('ab', 1).insert('ab', 2).insert('ab', 3)
42
+ assert_equal(t.find('ab').values.sort, [1, 2, 3])
43
+ assert_equal(t.find('a').values, [])
44
+ assert_equal(t.find('').values, [])
45
+ assert_equal(t.find_prefix('ab').values.sort, [1, 2, 3])
46
+ assert_equal(t.find_prefix('a').values.sort, [1, 2, 3])
47
+ assert_equal(t.find_prefix('').values.sort, [1, 2, 3])
48
+ end
49
+
50
+ # Test a more complex Trie that contains a few compressed keys.
51
+ def test_find_complex
52
+ t = Trie.new.insert('a', 1).insert('ab', 2).insert('abcdef', 3).
53
+ insert('b', 4).insert('bcd', 5).insert('b', 6).insert('bcd', 7)
54
+ assert_equal(t.find('a').values, [1])
55
+ assert_equal(t.find('ab').values, [2])
56
+ assert_equal(t.find('abcdef').values, [3])
57
+ assert_equal(t.find('b').values.sort, [4, 6])
58
+ assert_equal(t.find('bcd').values.sort, [5, 7])
59
+ assert_equal(t.find('bcde').values, [])
60
+ assert_equal(t.find('').values, [])
61
+ assert_equal(t.find_prefix('a').values, [1, 2, 3])
62
+ assert_equal(t.find_prefix('ab').values, [2, 3])
63
+ assert_equal(t.find_prefix('abcdef').values, [3])
64
+ assert_equal(t.find_prefix('b').values.sort, [4, 5, 6, 7])
65
+ assert_equal(t.find_prefix('bcd').values.sort, [5, 7])
66
+ assert_equal(t.find_prefix('bcde').values, [])
67
+ assert_equal(t.find_prefix('').values.sort, [1, 2, 3, 4, 5, 6, 7])
68
+ end
69
+
70
+ # We have a compressed key at the root and then do one-or
71
+ # two-characters-at-a-time searches against it.
72
+ def test_find_multiple_lookups_compressed_key
73
+ t = Trie.new.insert('alphabet', 1)
74
+ t2 = t.find_prefix('')
75
+ assert_equal(t2.values, [1])
76
+ t2 = t2.find_prefix('al')
77
+ assert_equal(t2.values, [1])
78
+ t2 = t2.find_prefix('p')
79
+ assert_equal(t2.values, [1])
80
+ t2 = t2.find_prefix('ha')
81
+ assert_equal(t2.values, [1])
82
+ t2 = t2.find_prefix('bet')
83
+ assert_equal(t2.values, [1])
84
+ t2 = t2.find_prefix('')
85
+ assert_equal(t2.values, [1])
86
+ t2 = t2.find_prefix('a')
87
+ assert_equal(t2.values, [])
88
+ end
89
+
90
+ # We construct a trie with multiple values and then walk down it,
91
+ # searching for one or two characters at a time.
92
+ def test_find_multiple_lookups
93
+ t = Trie.new.insert('happy', 1).insert('hop', 2).insert('hey', 3).
94
+ insert('hello!', 4).insert('help', 5).insert('foo', 6)
95
+ assert_equal(t.find_prefix('fo').values, [6])
96
+ t2 = t.find_prefix('h')
97
+ assert_equal(t2.values.sort, [1, 2, 3, 4, 5])
98
+ t2 = t2.find_prefix('e')
99
+ assert_equal(t2.values.sort, [3, 4, 5])
100
+ assert_equal(t2.find_prefix('y').values, [3])
101
+ t2 = t2.find_prefix('l')
102
+ assert_equal(t2.values.sort, [4, 5])
103
+ t2 = t2.find_prefix('lo')
104
+ assert_equal(t2.values, [4])
105
+ t2 = t2.find_prefix('!')
106
+ assert_equal(t2.values, [4])
107
+ t2 = t2.find_prefix('')
108
+ assert_equal(t2.values, [4])
109
+ t2 = t2.find_prefix('!')
110
+ assert_equal(t2.values, [])
111
+ end
112
+
113
+ # We construct a trie with multiple elements and test the size
114
+ # method.
115
+ def test_size
116
+ t = Trie.new.insert('ha', 1).insert('hat', 2).insert('hate', 3).
117
+ insert('hated', 4).insert('test', 5)
118
+ assert_equal(t.size, 5)
119
+ assert_equal(t.find_prefix('ha').size, 4)
120
+ assert_equal(t.find_prefix('hate').size, 2)
121
+ assert_equal(t.find_prefix('test').size, 1)
122
+ assert_equal(t.find_prefix('testing').size, 0)
123
+ end
124
+
125
+ # We build a trie and test the empty? method.
126
+ def test_empty
127
+ t = Trie.new.insert('foo', 1).insert('bar', 2).insert('food', 3)
128
+ assert_equal(t.empty?, false)
129
+ assert_equal(t.find('foo').empty?, false)
130
+ assert_equal(t.find_prefix('foo').empty?, false)
131
+ assert_equal(t.find('fool').empty?, true)
132
+ end
133
+
134
+ # We insert keys that are actually lists containing objects of varying
135
+ # classes.
136
+ def test_mixed_classes_in_keys
137
+ t = Trie.new.insert([0, 1, 2], 0).insert([0, 'a'], 1).insert([1000], 2).
138
+ insert([0, 'a'], 3).insert('blah', 4)
139
+ assert_equal(t.find_prefix([0]).values.sort, [0, 1, 3])
140
+ assert_equal(t.find_prefix([0, 1]).values, [0])
141
+ assert_equal(t.find_prefix([0, 'a']).values.sort, [1, 3])
142
+ assert_equal(t.find_prefix([1000]).values, [2])
143
+ assert_equal(t.find([0]).values, [])
144
+ assert_equal(t.find([0, 'a']).values.sort, [1, 3])
145
+ assert_equal(t.find('blah').values, [4])
146
+ end
147
+
148
+ # Test delete.
149
+ def test_delete
150
+ t = Trie.new.insert('a', 1).insert('a', 2).insert('a', 3).
151
+ insert('ab', 4).insert('ab', 5).insert('abc', 6)
152
+ assert_equal(t.values.sort, [1, 2, 3, 4, 5, 6])
153
+ t.delete('a')
154
+ assert_equal(t.values.sort, [4, 5, 6])
155
+ t.delete('abc')
156
+ assert_equal(t.values.sort, [4, 5])
157
+ t.delete('ab')
158
+ assert_equal(t.values, [])
159
+ end
160
+
161
+ # Test delete_pair.
162
+ def test_delete_pair
163
+ t = Trie.new.insert('apple', 1).insert('apples', 2)
164
+ assert_equal(t.find('apple').values, [1])
165
+ assert_equal(t.find_prefix('apple').values.sort, [1, 2])
166
+ t.delete_pair('apple', 1)
167
+ assert_equal(t.find('apple').values, [])
168
+ assert_equal(t.find('apples').values, [2])
169
+ assert_equal(t.find_prefix('apple').values, [2])
170
+ t.delete_pair('apples', 1) # key/value pair isn't in trie
171
+ assert_equal(t.find('apples').values, [2])
172
+ t.delete_pair('apples', 2)
173
+ assert_equal(t.find('apples').values, [])
174
+ end
175
+
176
+ # Test delete_value.
177
+ def test_delete_value
178
+ t = Trie.new.insert('a', 1).insert('ab', 1).insert('abc', 2).
179
+ insert('a', 2).insert('b', 1).insert('c', 1)
180
+ assert_equal(t.size, 6)
181
+ t.delete_value(1)
182
+ assert_equal(t.size, 2)
183
+ t.delete_value(2)
184
+ assert_equal(t.empty?, true)
185
+ end
186
+
187
+ # Test delete_prefix.
188
+ def test_delete_prefix
189
+ t = Trie.new.insert('a', 1).insert('a', 2).insert('a', 3).
190
+ insert('ab', 4).insert('ab', 5).insert('abc', 6)
191
+ assert_equal(t.values.sort, [1, 2, 3, 4, 5, 6])
192
+ t.delete_prefix('ab')
193
+ assert_equal(t.values.sort, [1, 2, 3])
194
+ t.delete_prefix('a')
195
+ assert_equal(t.empty?, true)
196
+ end
197
+
198
+ # Test clear.
199
+ def test_clear
200
+ t = Trie.new.insert('a', 1).insert('ab', 2)
201
+ assert_equal(t.size, 2)
202
+ t.clear
203
+ assert_equal(t.empty?, true)
204
+ end
205
+
206
+ # Test each_key.
207
+ def test_each_key
208
+ t = Trie.new.insert('a', 1).insert('a', 2).insert('b', 3).insert('ab', 4)
209
+ keys = []
210
+ t.each_key {|k| keys.push(k.join) }
211
+ assert_equal(keys.sort, ['a', 'ab', 'b'])
212
+ end
213
+
214
+ # Test each_value.
215
+ def test_each_value
216
+ t = Trie.new.insert('a', 1).insert('a', 2).insert('b', 1)
217
+ values = []
218
+ t.each_value {|v| values.push(v) }
219
+ assert_equal(values.sort, [1, 1, 2])
220
+ end
221
+
222
+ # Test each.
223
+ def test_each
224
+ t = Trie.new.insert('a', 1).insert('a', 2).insert('b', 3).insert('ab', 4)
225
+ pairs = []
226
+ t.each {|k, v| pairs.push([k.join, v]) }
227
+ assert_equal(pairs.sort, [['a', 1], ['a', 2], ['ab', 4], ['b', 3]])
228
+ end
229
+
230
+ # Test keys.
231
+ def test_keys
232
+ t = Trie.new.insert('a', 1).insert('a', 2).insert('abc', 3).insert('b', 4)
233
+ keys = t.keys.collect {|k| k.join }.sort
234
+ assert_equal(keys, ['a', 'abc', 'b'])
235
+ end
236
+
237
+ # Test the composition of the tries by using the num_nodes method.
238
+ def test_composition
239
+ t = Trie.new.insert('a', 1)
240
+ assert_equal(t.num_nodes, 1) # a
241
+ t.insert('a', 2)
242
+ assert_equal(t.num_nodes, 1) # a
243
+ t.insert('abc', 3)
244
+ assert_equal(t.num_nodes, 3) # '' -> a -> bc
245
+ t.insert('ab', 4)
246
+ assert_equal(t.num_nodes, 4) # '' -> a -> b -> c
247
+ t.insert('b', 5)
248
+ assert_equal(t.num_nodes, 5) # '' -> (a -> b -> c | b)
249
+ t.insert('b', 6)
250
+ assert_equal(t.num_nodes, 5) # '' -> (a -> b -> c | b)
251
+ t.insert('abcdef', 7)
252
+ assert_equal(t.num_nodes, 6) # '' -> (a -> b -> c -> def | b)
253
+ t.insert('abcdeg', 8)
254
+ # '' -> (a -> b -> c -> d -> e -> (f | g) | b)
255
+ assert_equal(t.num_nodes, 9)
256
+ end
257
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ SPEC = Gem::Specification.new do |s|
3
+ s.name = "trie"
4
+ s.version = "0.0.1"
5
+ s.author = "Daniel Erat"
6
+ s.email = "dan-ruby@erat.org"
7
+ s.homepage = "http://www.erat.org/ruby/"
8
+ s.platform = Gem::Platform::RUBY
9
+ s.summary = "Implemention of a trie data structure"
10
+ candidates = Dir.glob("{*,{lib,test}/*}")
11
+ s.files = candidates.delete_if {|i| i =~ /CVS/ }
12
+ s.require_path = "lib"
13
+ s.autorequire = "trie"
14
+ s.test_file = "test/tests.rb"
15
+ s.has_rdoc = true
16
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: trie
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2005-10-02 00:00:00 -07:00
8
+ summary: Implemention of a trie data structure
9
+ require_paths:
10
+ - lib
11
+ email: dan-ruby@erat.org
12
+ homepage: http://www.erat.org/ruby/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: trie
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ authors:
30
+ - Daniel Erat
31
+ files:
32
+ - MANIFEST
33
+ - COPYING
34
+ - INSTALL
35
+ - setup.rb
36
+ - README
37
+ - lib
38
+ - test
39
+ - trie.gemspec
40
+ - lib/trie.rb
41
+ - test/tests.rb
42
+ test_files:
43
+ - test/tests.rb
44
+ rdoc_options: []
45
+ extra_rdoc_files: []
46
+ executables: []
47
+ extensions: []
48
+ requirements: []
49
+ dependencies: []