itree 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ Dir[File.join(File.dirname(__FILE__),"itree","**","*.rb")].each do |file|
2
+ require file
3
+ end
@@ -0,0 +1,65 @@
1
+ module Intervals
2
+ class Node
3
+ attr_accessor :data, :scores, :subLeftMax, :subRightMax, :balance, :left, :right, :parent
4
+
5
+ def initialize(min,max,data)
6
+ raise ArgumentError.new("first agument cannot be greater than second argument") if min > max
7
+ @scores = [min,max]
8
+ @subLeftMax = nil
9
+ @subRightMax = nil
10
+ @balance = 0
11
+ @data = data
12
+ end
13
+
14
+ def <=>(other)
15
+ if @scores[0] != other.scores[0]
16
+ @scores[0] <=> other.scores[0]
17
+ else
18
+ other.scores[1] <=> @scores[1]
19
+ end
20
+ end
21
+
22
+ def ==(other)
23
+ @scores == other.scores
24
+ end
25
+
26
+ def resetBalance
27
+ case @balance
28
+ when -1
29
+ @left.balance = 0
30
+ @right.balance = 1
31
+ when 0
32
+ @left.balance = 0
33
+ @right.balance = 0
34
+ when 1
35
+ @left.balance = -1
36
+ @right.balance = 0
37
+ end
38
+ @balance = 0
39
+ end
40
+
41
+ def updateMaxScores
42
+ oldNodeMax = 0
43
+ locNode = self
44
+ while locNode
45
+ if locNode.left
46
+ oldNodeMax = locNode.left.scores[1]
47
+ oldNodeMax = (locNode.left.subLeftMax && (oldNodeMax < locNode.left.subLeftMax)) ? locNode.left.subLeftMax : oldNodeMax
48
+ oldNodeMax = (locNode.left.subRightMax && (oldNodeMax < locNode.left.subRightMax)) ? locNode.left.subRightMax : oldNodeMax
49
+ locNode.subLeftMax = oldNodeMax
50
+ else
51
+ locNode.subLeftMax = nil
52
+ end
53
+ if locNode.right
54
+ oldNodeMax = locNode.right.scores[1]
55
+ oldNodeMax = (locNode.right.subLeftMax && (oldNodeMax < locNode.right.subLeftMax)) ? locNode.right.subLeftMax : oldNodeMax
56
+ oldNodeMax = (locNode.right.subRightMax && (oldNodeMax < locNode.right.subRightMax)) ? locNode.right.subRightMax : oldNodeMax
57
+ locNode.subRightMax = oldNodeMax
58
+ else
59
+ locNode.subRightMax = nil
60
+ end
61
+ locNode = locNode.parent
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,389 @@
1
+ module Intervals
2
+ class Tree
3
+ attr_accessor :root, :size
4
+
5
+ def initialize
6
+ @root = nil
7
+ @size = 0
8
+ end
9
+
10
+ def insert(leftScore, rightScore, data=nil, updateData=false)
11
+ node = Node.new(leftScore,rightScore,data)
12
+ success = true
13
+
14
+ if @root.nil?
15
+ @root = node
16
+ else
17
+ balance,success = insertNode(@root,node,updateData)
18
+ end
19
+
20
+ @size = @size + 1 if success
21
+ return success
22
+ end
23
+
24
+ def insert!(leftScore, rightScore, data=nil)
25
+ return insert(leftScore,rightScore,data,true)
26
+ end
27
+
28
+ def stab(minScore,maxScore=nil)
29
+ maxScore = minScore if maxScore.nil?
30
+ results = []
31
+ stabNode(@root,minScore,maxScore,results) if @root
32
+ results
33
+ end
34
+
35
+ def remove(leftScore, rightScore)
36
+ if @root
37
+ delNode = Node.new(leftScore,rightScore,nil)
38
+ height,removed = removeNode(@root,delNode)
39
+ if removed
40
+ @size = @size - 1
41
+ @root = nil if @size == 0
42
+ return true
43
+ end
44
+ end
45
+ return false
46
+ end
47
+
48
+ private
49
+ def insertNode(locNode,insertNode,updateData=false)
50
+ diff = locNode <=> insertNode
51
+
52
+ if diff > 0
53
+ if locNode.left.nil?
54
+ locNode.left = insertNode
55
+ insertNode.parent = locNode
56
+ locNode.balance = locNode.balance - 1
57
+ locNode.updateMaxScores
58
+ if locNode.balance == 0
59
+ return 0,true
60
+ else
61
+ return 1,true
62
+ end
63
+ else
64
+ balanceUpdate,success = insertNode(locNode.left,insertNode,updateData)
65
+ if balanceUpdate != 0
66
+ locNode.balance = locNode.balance - 1
67
+ if locNode.balance == 0
68
+ return 0,success
69
+ elsif locNode.balance == -1
70
+ return 1,success
71
+ end
72
+
73
+ if locNode.left.balance < 0
74
+ rightRotation(locNode)
75
+ locNode.balance = 0
76
+ locNode.parent.balance = 0
77
+ locNode.subLeftMax = locNode.parent.subRightMax
78
+ locNode.parent.subRightMax = -Float::INFINITY
79
+ else
80
+ leftRotation(locNode.left)
81
+ rightRotation(locNode)
82
+ locNode.parent.resetBalance
83
+
84
+ locNode.subLeftMax = locNode.parent.subRightMax
85
+ locNode.parent.left.subRightMax = locNode.parent.subLeftMax
86
+ locNode.parent.subRightMax = -Float::INFINITY
87
+ locNode.parent.subLeftMax = -Float::INFINITY
88
+ end
89
+
90
+ locNode.parent.updateMaxScores
91
+ end
92
+ return 0,success
93
+ end
94
+ elsif diff < 0
95
+ if locNode.right.nil?
96
+ locNode.right = insertNode
97
+ insertNode.parent = locNode
98
+ locNode.balance = locNode.balance + 1
99
+ locNode.updateMaxScores
100
+ if locNode.balance == 0
101
+ return 0,true
102
+ else
103
+ return 1,true
104
+ end
105
+ else
106
+ balanceUpdate,success = insertNode(locNode.right,insertNode,updateData)
107
+ if balanceUpdate != 0
108
+ locNode.balance = locNode.balance + 1
109
+ if locNode.balance == 0
110
+ return 0,success
111
+ elsif locNode.balance == 1
112
+ return 1,success
113
+ end
114
+
115
+ if locNode.right.balance > 0
116
+ leftRotation(locNode)
117
+ locNode.balance = 0
118
+ locNode.parent.balance = 0
119
+ locNode.subRightMax = locNode.parent.subLeftMax
120
+ locNode.parent.subLeftMax = -Float::INFINITY
121
+ else
122
+ rightRotation(locNode.right)
123
+ leftRotation(locNode)
124
+ locNode.parent.resetBalance
125
+
126
+ locNode.subRightMax = locNode.parent.subLeftMax
127
+ locNode.parent.right.subLeftMax = locNode.parent.subRightMax
128
+ locNode.parent.subRightMax = -Float::INFINITY
129
+ locNode.parent.subLeftMax = -Float::INFINITY
130
+ end
131
+
132
+ locNode.parent.updateMaxScores
133
+ end
134
+ return 0,success
135
+ end
136
+ else
137
+ locNode.data = insertNode.data if updateData
138
+ return 0,false
139
+ end
140
+ end
141
+
142
+ def removeFromParent(locNode,replacementNode)
143
+ if locNode.parent
144
+ if locNode.parent.left == locNode
145
+ locNode.parent.left = replacementNode
146
+ else
147
+ locNode.parent.right = replacementNode
148
+ end
149
+ else
150
+ @root = replacementNode
151
+ end
152
+ end
153
+
154
+ def removeNode(locNode, delNode)
155
+ diff = locNode <=> delNode
156
+ heightDelta = 0
157
+ replacementNode = nil
158
+ removed = false
159
+
160
+ if diff == 0
161
+ if locNode.left.nil?
162
+ if locNode.right.nil?
163
+ removeFromParent(locNode,nil)
164
+ locNode.parent.updateMaxScores if locNode.parent
165
+ removed = true
166
+ return -1,removed
167
+ end
168
+ removeFromParent(locNode,locNode.right)
169
+ locNode.right.parent = locNode.parent
170
+ locNode.parent.updateMaxScores if locNode.parent
171
+ locNode.right = nil
172
+ removed = true
173
+ return -1,removed
174
+ end
175
+
176
+ if locNode.right.nil?
177
+ removeFromParent(locNode,locNode.left)
178
+ locNode.left.parent = locNode.parent
179
+ locNode.parent.updateMaxScores if locNode.parent
180
+ locNode.left = nil
181
+ removed = true
182
+ return -1,removed
183
+ end
184
+
185
+ if locNode.balance < 0
186
+ replacementNode = locNode.left
187
+ while replacementNode.right do
188
+ replacementNode = replacementNode.right
189
+ end
190
+ else
191
+ replacementNode = locNode.right
192
+ while replacementNode.left do
193
+ replacementNode = replacementNode.left
194
+ end
195
+ end
196
+
197
+ heightDelta,removed = removeNode(locNode,replacementNode)
198
+
199
+ locNode.right.parent = replacementNode if locNode.right
200
+ locNode.left.parent = replacementNode if locNode.left
201
+
202
+ replacementNode.left = locNode.left
203
+ replacementNode.right = locNode.right
204
+ replacementNode.parent = locNode.parent
205
+ replacementNode.balance = locNode.balance
206
+
207
+ if locNode == @root
208
+ @root = replacementNode
209
+ replacementNode.updateMaxScores
210
+ else
211
+ if locNode == locNode.parent.left
212
+ locNode.parent.left = replacementNode
213
+ else
214
+ locNode.parent.right = replacementNode
215
+ end
216
+ replacementNode.updateMaxScores
217
+ end
218
+
219
+ locNode.left = nil
220
+ locNode.right = nil
221
+
222
+ if replacementNode.balance == 0
223
+ return heightDelta,removed
224
+ end
225
+ removed = true
226
+ return 0,removed
227
+ elsif diff > 0
228
+ if locNode.left
229
+ heightDelta,removed = removeNode(locNode.left,delNode)
230
+ if heightDelta
231
+ locNode.balance = locNode.balance + 1
232
+ if locNode.balance == 0
233
+ return -1,removed
234
+ elsif locNode.balance == 1
235
+ return 0,removed
236
+ end
237
+
238
+ if locNode.right.balance == 1
239
+ leftRotation(locNode)
240
+ locNode.parent.balance = 0
241
+ locNode.parent.left.balance = 0
242
+
243
+ locNode.subRightMax = locNode.parent.subLeftMax
244
+ locNode.parent.subLeftMax = nil
245
+ locNode.parent.updateMaxScores
246
+
247
+ return -1,removed
248
+ elsif locNode.right.balance == 0
249
+ leftRotation(locNode)
250
+ locNode.parent.balance = -1
251
+ locNode.parent.left.balance = 1
252
+
253
+ locNode.subRightMax = locNode.parent.subLeftMax
254
+ locNode.parent.subLeftMax = nil
255
+ locNode.parent.updateMaxScores
256
+
257
+ return 0,removed
258
+ end
259
+ rightRotation(locNode.right)
260
+ leftRotation(locNode)
261
+ locNode.parent.resetBalance
262
+
263
+ locNode.subRightMax = locNode.parent.subLeftMax
264
+ locNode.parent.right.subLeftMax = locNode.parent.subRightMax
265
+
266
+ locNode.parent.subRightMax = nil
267
+ locNode.parent.subLeftMax = nil
268
+ locNode.parent.updateMaxScores
269
+
270
+ return -1,removed
271
+ end
272
+ end
273
+ elsif diff < 0
274
+ if locNode.right
275
+ heightDelta,removed = removeNode(locNode.right,delNode)
276
+ if heightDelta
277
+ locNode.balance = locNode.balance - 1
278
+ if locNode.balance == 0
279
+ return 1,removed
280
+ elsif locNode.balance == -1
281
+ return 0,removed
282
+ end
283
+
284
+ if locNode.left.balance == -1
285
+ rightRotation(locNode)
286
+ locNode.parent.balance = 0
287
+ locNode.parent.right.balance = 0
288
+
289
+ locNode.subLeftMax = locNode.parent.subRightMax
290
+ locNode.parent.subRightMax = nil
291
+ locNode.parent.updateMaxScores
292
+
293
+ return -1,removed
294
+ elsif locNode.left.balance == 0
295
+ rightRotation(locNode)
296
+ locNode.parent.balance = 1
297
+ locNode.parent.right.balance = -1
298
+
299
+ locNode.subLeftMax = locNode.parent.subRightMax
300
+ locNode.parent.subRightMax = nil
301
+ locNode.parent.updateMaxScores
302
+
303
+ return 0,removed
304
+ end
305
+ leftRotation(locNode.left)
306
+ rightRotation(locNode)
307
+ locNode.parent.resetBalance
308
+
309
+ locNode.subLeftMax = locNode.parent.subRightMax
310
+ locNode.parent.left.subRightMax = locNode.parent.subLeftMax
311
+
312
+ locNode.parent.subLeftMax = nil
313
+ locNode.parent.subRightMax = nil
314
+ locNode.parent.updateMaxScores
315
+
316
+ return -1,removed
317
+ end
318
+ end
319
+ end
320
+
321
+ return 0,removed
322
+ end
323
+
324
+ def leftRotation(locNode)
325
+ newRoot = locNode.right
326
+ locNode.right = newRoot.left
327
+ if locNode.right
328
+ locNode.right.parent = locNode
329
+ end
330
+ newRoot.left = locNode
331
+
332
+ newRoot.parent = locNode.parent
333
+ locNode.parent = newRoot
334
+ if newRoot.parent
335
+ if ((newRoot.parent <=> newRoot) > -1)
336
+ newRoot.parent.left = newRoot
337
+ else
338
+ newRoot.parent.right = newRoot
339
+ end
340
+ else
341
+ @root = newRoot
342
+ end
343
+ end
344
+
345
+ def rightRotation(locNode)
346
+ newRoot = locNode.left
347
+ locNode.left = newRoot.right
348
+ if locNode.left
349
+ locNode.left.parent = locNode
350
+ end
351
+ newRoot.right = locNode
352
+
353
+ newRoot.parent = locNode.parent
354
+ locNode.parent = newRoot
355
+ if newRoot.parent
356
+ if ((newRoot.parent <=> newRoot) > -1)
357
+ newRoot.parent.left = newRoot
358
+ else
359
+ newRoot.parent.right = newRoot
360
+ end
361
+ else
362
+ @root = newRoot
363
+ end
364
+ end
365
+
366
+ def stabNode(node, minScore, maxScore, results)
367
+ if node.subRightMax &&
368
+ minScore > node.subRightMax &&
369
+ node.subLeftMax &&
370
+ minScore > node.subLeftMax &&
371
+ minScore > node.scores[1]
372
+ return
373
+ end
374
+ if node.left
375
+ stabNode(node.left, minScore, maxScore, results)
376
+ end
377
+
378
+ if minScore >= node.scores[0] && maxScore <= node.scores[1]
379
+ results << node.clone
380
+ end
381
+
382
+ return if maxScore < node.scores[0]
383
+
384
+ if node.right
385
+ stabNode(node.right, minScore, maxScore, results)
386
+ end
387
+ end
388
+ end
389
+ end
@@ -0,0 +1,3 @@
1
+ module Intervals
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+
3
+ describe Intervals::Node do
4
+ context "creation" do
5
+ describe "#initialize" do
6
+ it { Intervals::Node.new(1,2,"taco").scores.should eq [1,2]}
7
+ it { Intervals::Node.new(1,2,"taco").data.should eq "taco"}
8
+ it { Intervals::Node.new(1,2,"taco").balance.should eq 0}
9
+ it { expect { Intervals::Node.new(2,1,"taco") }.to raise_error(ArgumentError)}
10
+ end
11
+ end
12
+
13
+ context "comparing" do
14
+ let(:lesser_min_node) { Intervals::Node.new(0,5,nil) }
15
+ let(:greater_min_node) { Intervals::Node.new(1,5,nil) }
16
+ let(:lesser_max_node) { Intervals::Node.new(0,5,nil) }
17
+ let(:greater_max_node) { Intervals::Node.new(0,1,nil) }
18
+
19
+ describe "#<=>" do
20
+ it { (lesser_min_node <=> greater_min_node).should eq -1 }
21
+ it { (lesser_min_node <=> lesser_min_node).should eq 0 }
22
+ it { (greater_min_node <=> lesser_min_node).should eq 1 }
23
+ it { (lesser_max_node <=> greater_max_node).should eq -1 }
24
+ it { (lesser_max_node <=> lesser_max_node).should eq 0 }
25
+ it { (greater_max_node <=> lesser_max_node).should eq 1 }
26
+ end
27
+
28
+ describe "#==" do
29
+ it { (lesser_min_node == lesser_min_node).should be true }
30
+ it { (lesser_min_node == greater_min_node).should_not be true }
31
+ it { (greater_min_node == greater_min_node).should be true }
32
+ end
33
+ end
34
+
35
+ describe "#resetBalance" do
36
+ let(:node) do
37
+ n = Intervals::Node.new(5,10,nil)
38
+ n.left = Intervals::Node.new(0,5,nil)
39
+ n.left.balance = 2
40
+ n.right = Intervals::Node.new(15,20,nil)
41
+ n.right.balance = 2
42
+ n
43
+ end
44
+
45
+ it "resets balance to 0" do
46
+ node.balance = 1
47
+ node.resetBalance
48
+ node.balance.should eq 0
49
+ end
50
+
51
+ context "when balance is -1" do
52
+ before(:each) { node.balance = -1 }
53
+
54
+ it "sets left child balance to 0" do
55
+ node.resetBalance
56
+ node.left.balance.should eq 0
57
+ end
58
+
59
+ it "sets right child balance to 1" do
60
+ node.resetBalance
61
+ node.right.balance.should eq 1
62
+ end
63
+ end
64
+
65
+ context "when balance is 0" do
66
+ before(:each) { node.balance = 0 }
67
+
68
+ it "sets left child balance to 0" do
69
+ node.resetBalance
70
+ node.left.balance.should eq 0
71
+ end
72
+
73
+ it "sets right child balance to 0" do
74
+ node.resetBalance
75
+ node.right.balance.should eq 0
76
+ end
77
+ end
78
+
79
+ context "when balance is 1" do
80
+ before(:each) { node.balance = 1 }
81
+
82
+ it "sets left child balance to -1" do
83
+ node.resetBalance
84
+ node.left.balance.should eq -1
85
+ end
86
+
87
+ it "sets right child balance to 0" do
88
+ node.resetBalance
89
+ node.right.balance.should eq 0
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "#updateMaxScores" do
95
+ let(:node) do
96
+ n = Intervals::Node.new(5,10,nil)
97
+ n.left = Intervals::Node.new(0,5,nil)
98
+ n.left.parent = n
99
+ n.right = Intervals::Node.new(15,20,nil)
100
+ n.right.parent = n
101
+ n.left.left = Intervals::Node.new(-2,0,nil)
102
+ n.left.left.parent = n.left
103
+ n.left.right = Intervals::Node.new(3,5,nil)
104
+ n.left.right.parent = n.left
105
+ n.right.left = Intervals::Node.new(10,15,nil)
106
+ n.right.left.parent = n.right
107
+ n.right.right = Intervals::Node.new(20,25,nil)
108
+ n.right.right.parent = n.right
109
+ n
110
+ end
111
+
112
+ context "left-left child has largest max score" do
113
+ before(:each) { node.left.left.scores[1] = 100 }
114
+
115
+ it "sets the maxLeftScore to the max score of the left-left child" do
116
+ node.left.left.updateMaxScores
117
+ node.subLeftMax.should eq node.left.left.scores[1]
118
+ end
119
+ end
120
+
121
+ context "left-right child has largest max score" do
122
+ before(:each) { node.left.right.scores[1] = 100 }
123
+
124
+ it "sets the maxLeftScore to the max score of the left-right child" do
125
+ node.left.right.updateMaxScores
126
+ node.subLeftMax.should eq node.left.right.scores[1]
127
+ end
128
+ end
129
+
130
+ context "right-left child has largest max score" do
131
+ before(:each) { node.right.left.scores[1] = 100 }
132
+
133
+ it "sets the maxRightScore to the max score of the right-left child" do
134
+ node.right.left.updateMaxScores
135
+ node.subRightMax.should eq node.right.left.scores[1]
136
+ end
137
+ end
138
+
139
+ context "right-right child has largest max score" do
140
+ before(:each) { node.right.right.scores[1] = 100 }
141
+
142
+ it "sets the maxRightScore to the max score of the right-right child" do
143
+ node.right.right.updateMaxScores
144
+ node.subRightMax.should eq node.right.right.scores[1]
145
+ end
146
+ end
147
+ end
148
+
149
+ end
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+
3
+ describe Intervals::Tree do
4
+ let(:tree) { Intervals::Tree.new }
5
+
6
+ context "creation" do
7
+ describe "#initialize" do
8
+ it { Intervals::Tree.new.size.should eq 0}
9
+ it { Intervals::Tree.new.root.should be nil}
10
+ end
11
+ end
12
+
13
+ describe "#insert" do
14
+ context "insert node in empty tree" do
15
+ it "inserts at root" do
16
+ tree.insert(0,10)
17
+ tree.root.scores.should eq [0,10]
18
+ end
19
+
20
+ it "increases tree size" do
21
+ tree.insert(0,10)
22
+ tree.size.should eq 1
23
+ end
24
+ end
25
+
26
+ context "inserting duplicates" do
27
+ before(:each) { tree.insert(0,10)}
28
+
29
+ it { tree.insert(0,10,"taco").should_not be true}
30
+ it "does not increase tree size" do
31
+ tree.insert(0,10,"taco")
32
+ tree.size.should_not eq 2
33
+ end
34
+ end
35
+
36
+ context "rotations" do
37
+ before(:each) do
38
+ tree.insert(150,250)
39
+ tree.insert(200,300)
40
+ tree.insert(100,200)
41
+ end
42
+
43
+ it { tree.root.scores.should eq [150,250] }
44
+ it { tree.root.left.scores.should eq [100,200] }
45
+ it { tree.root.right.scores.should eq [200,300] }
46
+ it { tree.size.should eq 3 }
47
+
48
+ context "left-left rotation" do
49
+ before(:each) do
50
+ tree.insert(25,50)
51
+ tree.insert(0,25)
52
+ end
53
+
54
+ it "does not change root" do
55
+ tree.root.scores.should eq [150,250]
56
+ end
57
+ it { tree.root.left.scores.should eq [25,50] }
58
+ it { tree.root.left.left.scores.should eq [0,25] }
59
+ it { tree.root.left.right.scores.should eq [100,200] }
60
+ it { tree.root.subLeftMax.should eq 200 }
61
+ end
62
+
63
+ context "right-right rotation" do
64
+ before(:each) do
65
+ tree.insert(250,300)
66
+ tree.insert(300,350)
67
+ end
68
+
69
+ it "does not change root" do
70
+ tree.root.scores.should eq [150,250]
71
+ end
72
+ it { tree.root.right.scores.should eq [250,300] }
73
+ it { tree.root.right.left.scores.should eq [200,300] }
74
+ it { tree.root.right.right.scores.should eq [300,350] }
75
+ it { tree.root.subRightMax.should eq 350 }
76
+ end
77
+
78
+ context "left-right rotation" do
79
+ before(:each) do
80
+ tree.insert(50,100)
81
+ tree.insert(75,125)
82
+ end
83
+
84
+ it "does not change root" do
85
+ tree.root.scores.should eq [150,250]
86
+ end
87
+ it { tree.root.left.scores.should eq [75,125] }
88
+ it { tree.root.left.left.scores.should eq [50,100] }
89
+ it { tree.root.left.right.scores.should eq [100,200] }
90
+ it { tree.root.subLeftMax.should eq 200 }
91
+ end
92
+
93
+ context "right-left rotation" do
94
+ before(:each) do
95
+ tree.insert(250,300)
96
+ tree.insert(225,275)
97
+ end
98
+
99
+ it "does not change root" do
100
+ tree.root.scores.should eq [150,250]
101
+ end
102
+ it { tree.root.right.scores.should eq [225,275] }
103
+ it { tree.root.right.left.scores.should eq [200,300] }
104
+ it { tree.root.right.right.scores.should eq [250,300] }
105
+ it { tree.root.subRightMax.should eq 300 }
106
+ end
107
+ end
108
+
109
+ end
110
+
111
+ describe "#insert!" do
112
+ context "inserting duplicates" do
113
+ before(:each) { tree.insert(0,10,"cheese")}
114
+
115
+ it { tree.root.data.should eq "cheese" }
116
+ it { tree.insert!(0,10,"taco").should_not be true}
117
+ it "does not increase tree size" do
118
+ tree.insert!(0,10,"taco")
119
+ tree.size.should_not eq 2
120
+ end
121
+ it "updates the node data" do
122
+ tree.insert!(0,10,"taco")
123
+ tree.root.data.should eq "taco"
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "#remove" do
129
+ before(:each) do
130
+ tree.insert(100,200)
131
+ tree.insert(200,300)
132
+ tree.insert(150,250)
133
+ tree.insert(300,400)
134
+ tree.insert(400,500)
135
+ tree.insert(50,100)
136
+ tree.insert(75,125)
137
+ tree.insert(25,50)
138
+ tree.insert(0,25)
139
+ tree.insert(51,101)
140
+ end
141
+
142
+
143
+ end
144
+
145
+ describe "#stab" do
146
+ before(:each) do
147
+ tree.insert(100,200)
148
+ tree.insert(200,300)
149
+ tree.insert(150,250)
150
+ tree.insert(300,400)
151
+ tree.insert(400,500)
152
+ tree.insert(50,100)
153
+ tree.insert(75,125)
154
+ tree.insert(25,50)
155
+ tree.insert(0,25)
156
+ tree.insert(51,101)
157
+ tree.remove(100,200)
158
+ tree.remove(50,100)
159
+ end
160
+
161
+ it { tree.remove(0,25).should be true }
162
+ it { tree.remove(0,24).should be false }
163
+
164
+ it { tree.stab(23).length.should eq 1 }
165
+ it "returns a single range" do
166
+ results = tree.stab(23).map{|n| n.scores }.sort{|a,b| a[0] <=> b[0]}
167
+ results[0].should eq [0,25]
168
+ end
169
+
170
+ it { tree.stab(40).length.should eq 1 }
171
+ it "returns a single range" do
172
+ results = tree.stab(40).map{|n| n.scores }.sort{|a,b| a[0] <=> b[0]}
173
+ results[0].should eq [25,50]
174
+ end
175
+
176
+ it { tree.stab(77).length.should eq 2 }
177
+ it "returns two ranges" do
178
+ results = tree.stab(77).map{|n| n.scores }.sort{|a,b| a[0] <=> b[0]}
179
+ results[0].should eq [51,101]
180
+ results[1].should eq [75,125]
181
+ end
182
+
183
+ it { tree.stab(175).length.should eq 1 }
184
+ it "returns a single range" do
185
+ results = tree.stab(175).map{|n| n.scores }.sort{|a,b| a[0] <=> b[0]}
186
+ results[0].should eq [150,250]
187
+ end
188
+
189
+ it { tree.stab(350).length.should eq 1 }
190
+ it "returns a single range" do
191
+ results = tree.stab(350).map{|n| n.scores }.sort{|a,b| a[0] <=> b[0]}
192
+ results[0].should eq [300,400]
193
+ end
194
+ end
195
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kenny Hoxworth
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Interval Tree Data Structure
31
+ email:
32
+ - hoxworth@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/itree/node.rb
38
+ - lib/itree/tree.rb
39
+ - lib/itree/version.rb
40
+ - lib/itree.rb
41
+ - spec/node_spec.rb
42
+ - spec/tree_spec.rb
43
+ homepage: http://github.com/hoxworth/itree
44
+ licenses: []
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.24
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Interval Tree Data Structure
67
+ test_files:
68
+ - spec/node_spec.rb
69
+ - spec/tree_spec.rb