itree 0.1.0

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