Skip to content

Commit 43877b5

Browse files
committed
finish adding min/max type methods and relevant tests
1 parent fcec4ae commit 43877b5

File tree

4 files changed

+68
-26
lines changed

4 files changed

+68
-26
lines changed

src/main/scala/BPlusTree.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,23 @@ abstract class BPlusTree[K <% Ordered[K], +V] {
256256
case (true, leaf, index) => nextPosition( leaf, index )
257257
case (false, leaf, index) => (leaf, index)
258258
}
259+
260+
/**
261+
* Returns the leaf position of the key that is greatest less than or equal to `key`.
262+
**/
263+
protected def greatestLTE( key: K ) =
264+
lookupLTE( key ) match {
265+
case (_, leaf, index) => (leaf, index)
266+
}
267+
268+
/**
269+
* Returns the leaf position of the key that is greatest less than `key`.
270+
**/
271+
protected def greatestLT( key: K ) =
272+
lookupLTE( key ) match {
273+
case (true, leaf, index) => prevPosition( leaf, index )
274+
case (false, leaf, index) => (leaf, index)
275+
}
259276

260277
/**
261278
* Returns the key/value pair whose key is least greater than or equal to `key`.
@@ -266,6 +283,16 @@ abstract class BPlusTree[K <% Ordered[K], +V] {
266283
* Returns the key/value pair whose key is least greater than `key`.
267284
*/
268285
def leastGreaterThan( key: K ) = optionalKeyValue( leastGT(key) )
286+
287+
/**
288+
* Returns the key/value pair whose key is greatest less than or equal to `key`.
289+
*/
290+
def greatestLessThanOrEqual( key: K ) = optionalKeyValue( greatestLTE(key) )
291+
292+
/**
293+
* Returns the key/value pair whose key is greatest less than `key`.
294+
*/
295+
def greatestLessThan( key: K ) = optionalKeyValue( greatestLT(key) )
269296

270297
/**
271298
* Returns a bounded iterator over a range of key/value pairs in the tree in ascending sorted key order. The range of key/value pairs in the iterator is specified by `bounds`. `bounds` must contain one or two pairs where the first element in the pair is a symbol corresponding to the type of bound (i.e. '<, '<=, '>, '>=) and the second element is a key value.

src/test/scala/FileSpecificTests.scala

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import collection.mutable.HashSet
1111

1212
class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
1313

14+
val insertions = 30
15+
1416
"persistence" in {
1517
val f = newfile
1618
val t = new FileBPlusTree[Int, Any]( f, 3 )
@@ -26,7 +28,6 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
2628
"inserting/deleting/retrieving long strings" in {
2729
val t = new FileBPlusTree[Int, String]( newfile, 3 )
2830
val set = new HashSet[String]
29-
val size = 50
3031
val len = 500
3132

3233
def string: String = {
@@ -40,12 +41,12 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
4041
}
4142
}
4243

43-
for (k <- 1 to size) {
44+
for (k <- 1 to insertions) {
4445
t.insert( k, string ) shouldBe false
4546
t.wellConstructed shouldBe "true"
4647
}
4748

48-
for (k <- 1 to size/2) {
49+
for (k <- 1 to insertions/2) {
4950
t.search( k ) match {
5051
case None => fail
5152
case Some( v ) => set -= v
@@ -55,12 +56,12 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
5556
t.wellConstructed shouldBe "true"
5657
}
5758

58-
for (k <- size + 1 to 2*size) {
59+
for (k <- insertions + 1 to 2*insertions) {
5960
t.insert( k, string ) shouldBe false
6061
t.wellConstructed shouldBe "true"
6162
}
6263

63-
for (k <- size/2 + 1 to size) {
64+
for (k <- insertions/2 + 1 to insertions) {
6465
t.search( k ) match {
6566
case None => fail
6667
case Some( v ) => set -= v
@@ -70,15 +71,14 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
7071
t.wellConstructed shouldBe "true"
7172
}
7273

73-
assert( t.keysIterator.toList == (size + 1 to 2*size) )
74+
assert( t.keysIterator.toList == (insertions + 1 to 2*insertions) )
7475
assert( t.valuesIterator.toSet == set )
7576
}
7677

7778
"inserting/deleting/retrieving maps" in {
7879
val t = new FileBPlusTree[Int, collection.Map[Int, String]]( newfile, 3 )
7980
val sset = new HashSet[String]
8081
val mset = new HashSet[collection.Map[Int, String]]
81-
val size = 50
8282
val len = 500
8383

8484
def map: collection.Map[Int, String] = {
@@ -94,12 +94,12 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
9494
}
9595
}
9696

97-
for (k <- 1 to size) {
97+
for (k <- 1 to insertions) {
9898
t.insert( k, map ) shouldBe false
9999
t.wellConstructed shouldBe "true"
100100
}
101101

102-
for (k <- 1 to size/2) {
102+
for (k <- 1 to insertions/2) {
103103
t.search( k ) match {
104104
case None => fail
105105
case Some( v ) =>
@@ -113,12 +113,12 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
113113
t.wellConstructed shouldBe "true"
114114
}
115115

116-
for (k <- size + 1 to 2*size) {
116+
for (k <- insertions + 1 to 2*insertions) {
117117
t.insert( k, map ) shouldBe false
118118
t.wellConstructed shouldBe "true"
119119
}
120120

121-
for (k <- size/2 + 1 to size) {
121+
for (k <- insertions/2 + 1 to insertions) {
122122
t.search( k ) match {
123123
case None => fail
124124
case Some( v ) =>
@@ -132,15 +132,14 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
132132
t.wellConstructed shouldBe "true"
133133
}
134134

135-
assert( t.keysIterator.toList == (size + 1 to 2*size) )
135+
assert( t.keysIterator.toList == (insertions + 1 to 2*insertions) )
136136
assert( t.valuesIterator.toSet == mset )
137137
}
138138

139139
"inserting/deleting/retrieving arrays" in {
140140
val t = new FileBPlusTree[Int, collection.Seq[String]]( newfile, 3 )
141141
val sset = new HashSet[String]
142142
val lset = new HashSet[collection.Seq[String]]
143-
val size = 50
144143
val len = 500
145144

146145
def seq: collection.Seq[String] = {
@@ -156,12 +155,12 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
156155
}
157156
}
158157

159-
for (k <- 1 to size) {
158+
for (k <- 1 to insertions) {
160159
t.insert( k, seq ) shouldBe false
161160
t.wellConstructed shouldBe "true"
162161
}
163162

164-
for (k <- 1 to size/2) {
163+
for (k <- 1 to insertions/2) {
165164
t.search( k ) match {
166165
case None => fail
167166
case Some( v ) =>
@@ -173,12 +172,12 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
173172
t.wellConstructed shouldBe "true"
174173
}
175174

176-
for (k <- size + 1 to 2*size) {
175+
for (k <- insertions + 1 to 2*insertions) {
177176
t.insert( k, seq ) shouldBe false
178177
t.wellConstructed shouldBe "true"
179178
}
180179

181-
for (k <- size/2 + 1 to size) {
180+
for (k <- insertions/2 + 1 to insertions) {
182181
t.search( k ) match {
183182
case None => fail
184183
case Some( v ) =>
@@ -192,7 +191,7 @@ class FileSpecificTests extends FreeSpec with PropertyChecks with Matchers {
192191
t.wellConstructed shouldBe "true"
193192
}
194193

195-
assert( t.keysIterator.toList == (size + 1 to 2*size) )
194+
assert( t.keysIterator.toList == (insertions + 1 to 2*insertions) )
196195
assert( t.valuesIterator.toSet == lset )
197196
}
198197

src/test/scala/MiscTests.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,26 @@ class MiscTests extends FreeSpec with PropertyChecks with Matchers {
1717
t.maxKey shouldBe None
1818
t.leastGreaterThanOrEqual( 3 ) shouldBe None
1919
t.leastGreaterThan( 3 ) shouldBe None
20+
t.greatestLessThanOrEqual( 3 ) shouldBe None
21+
t.greatestLessThan( 3 ) shouldBe None
2022
t.insert( 5, 'five )
2123
t.min shouldBe Some((5, 'five))
2224
t.max shouldBe Some((5, 'five))
2325
t.minKey shouldBe Some(5)
2426
t.maxKey shouldBe Some(5)
27+
2528
t.leastGreaterThanOrEqual( 3 ) shouldBe Some((5, 'five))
2629
t.leastGreaterThan( 3 ) shouldBe Some((5, 'five))
2730
t.leastGreaterThanOrEqual( 5 ) shouldBe Some((5, 'five))
2831
t.leastGreaterThan( 5 ) shouldBe None
2932
t.leastGreaterThanOrEqual( 6 ) shouldBe None
3033
t.leastGreaterThan( 6 ) shouldBe None
34+
t.greatestLessThanOrEqual( 3 ) shouldBe None
35+
t.greatestLessThan( 3 ) shouldBe None
36+
t.greatestLessThanOrEqual( 5 ) shouldBe Some((5, 'five))
37+
t.greatestLessThan( 5 ) shouldBe None
38+
t.greatestLessThanOrEqual( 6 ) shouldBe Some((5, 'five))
39+
t.greatestLessThan( 6 ) shouldBe Some((5, 'five))
3140
t.insert( 3, 'three )
3241
t.min shouldBe Some((3, 'three))
3342
t.max shouldBe Some((5, 'five))
@@ -39,6 +48,17 @@ class MiscTests extends FreeSpec with PropertyChecks with Matchers {
3948
t.leastGreaterThan( 3 ) shouldBe Some((5, 'five))
4049
t.leastGreaterThanOrEqual( 5 ) shouldBe Some((5, 'five))
4150
t.leastGreaterThan( 5 ) shouldBe None
51+
t.leastGreaterThanOrEqual( 6 ) shouldBe None
52+
t.leastGreaterThan( 6 ) shouldBe None
53+
54+
t.greatestLessThanOrEqual( 2 ) shouldBe None
55+
t.greatestLessThan( 2 ) shouldBe None
56+
t.greatestLessThanOrEqual( 3 ) shouldBe Some((3, 'three))
57+
t.greatestLessThan( 3 ) shouldBe None
58+
t.greatestLessThanOrEqual( 5 ) shouldBe Some((5, 'five))
59+
t.greatestLessThan( 5 ) shouldBe Some((3, 'three))
60+
t.greatestLessThanOrEqual( 6 ) shouldBe Some((5, 'five))
61+
t.greatestLessThan( 6 ) shouldBe Some((5, 'five))
4262
}
4363

4464
}

src/test/scala/TestMain.scala

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ object TestMain extends App {
77

88
val t = new FileBPlusTree[Int, String]( newfile, 3 )
99

10-
t.insert( 1, "a"*500 )
11-
t.insert( 2, "b"*500 )
12-
t.insert( 3, "c"*500 )
13-
t.insert( 4, "d"*500 )
14-
t.insert( 5, "e"*500 )
15-
println( t.wellConstructed )
16-
println( t.iterator.toList )
17-
println( t.search(3) )
10+
t.insert( 3, "a" )
11+
t.insert( 5, "b" )
12+
println( t.greatestLessThan(3) )
13+
1814
}

0 commit comments

Comments
 (0)