CSSE 230
2D Tree Programming Assignment
Instructions
The purpose of this exercise is to understand in detail the
mechanics of insertion, search, and finding the nearest neighbor in 2D
Trees.
This
is an individual assignment, Two2Trees, in your individual repository.
All the methods you are to write are in the TwoDTree class, but you may
modify other classes if you like.
We discussed how to build 2D trees in class using the insert(point,
label) algorithm. Start by implementing this.
Commit your code now and regularly as you work, at least after
finishing each method.
Next, write a contains() method to see if a point is stored in
a 2D tree.
Finally, write nearestNeighbor().
Each
of these three algorithms must operate in O(log n) time on a collection
of n points. This will be true if you follow the algorithms given in
class.
Your final submission will be tested using the given unit
tests, and probably some more. You should write as many additional unit
tests as you need to show that your algorithms work. We may
also
test it using the given visualizer. We recommend doing the same, and if
you find any case that breaks an algorithm, turning it into a unit test
that you submit.
For more details, we'd recommend these sources:
- The slides (details of nearest neighbor search)
- The template code in your repo.
- The Wikipedia
article.
This shows how to build a balanced tree if you start with the whole
collection. A nice idea, but we are adding points one at a time.
Implementing rotations in 2D trees is beyond the scope of this
assignment. You're welcome.
Hints:
- The direction of each node is given in an
enumeration called Direction.
The root always splits the plane depending on its point's x-coordinate, so has
direction of Direction.X. This is shown using a vertical line (see node
A below) since splitting based on X splits the plane using a vertical
line. The root's children split the plane depending on the y-coordinate, so
will be of type Direction.Y (the horizontal lines on E and B below).
- The given RectHV class stores
rectangle bounds. You'll probably want each node to store
the rectangle it is part of. For example, the root could
have been a point from anywhere on the plane, so it store the
rectangle from (0,0) - (1,1). Say the root is at (0.3, 0.6).
Then any node inserted to its left needs to have an x-coordinate
< 0.3. So when inserted, this left child will store the
rectangle bounds (0,0) - (0.3, 1). If a right child is inserted,
it will
store the bounds (0.3, 0) - (1, 1). It requires some work to store the
correct rectangle bounds. But if you do, then in the nearestNeighbor
algorithm, when you want to check to see if a point could be
closer before recursing to a node, you can just call the RectHV's
distanceTo(Point2)
method to do the
calculation of the distance from the point to the
rectangle.
- You can use and modify the visualizer if you like. (We won't run it when we test your code.) If you do,
- When you add a node, store it's depth in the given
field. This will let the tree visualizer (on the left side of the
screenshot below) to place the nodes correctly.
- Left-clicking inserts a point.
- Right-clicking adds a query point for the nearest neighbor algorithm. This point will be blue. If you want it to highlight the nearest point found in red, then set the nearestFound field in TwoDTree to be the closest point you found.
Make sure you do a final commit of your code.
Here's the screenshot of a tree used frequently in the unit tests: