Week 5 Assignment - Princeton-Algorithms-PartI

来源:互联网 发布:淘宝店铺全屏怎么装修 编辑:程序博客网 时间:2024/06/05 16:27

题注

最近实在是太忙了,主要是又进入了论文周期,技术方案刚刚确定,估计后面的3周要一直写论文… 本来打算这一阵子不更新技术博客了,没想到CSDN的朋友们有的还等着我写Week 5的Assignment呢!我这人就怕让别人等… 于是就花了整个一中午的时间把这个东西写完了。为什么这么快呢?第一个原因是以前Stanford在Coursera中也开过一门算法课,叫做《Algorithm: Design and Analysis I》,那里面也用到了KdTree,原始的代码我还留着。第二个原因是,KdTree搜索最近Point2D是一个很模块化的东西,网上实际上是有现成的代码的,甚至国外的友人们也有用Princeton的Stdlib做的。所以,Week5的Assignment我基本上结合了上面的两套代码,组合成了自己的代码,其主体框架用的是国外友人的,因为代码结构更清晰~

国外友人针对这一问题答案的链接为:https://gist.github.com/agjacome/5246693。有兴趣的朋友们可以看一下,不过其没有太多的分析。也难怪啦,Assignment题目中对于算法的描述已经非常清楚了,结合课程本身里面KdTree章节的讲解,相信大家只要认真写,是肯定可以写出来的。

题目

Write a data typeto represent a set of points in the unit square (all points havex- and y-coordinates between 0 and 1)using a 2d-tree to supportefficientrange search (find all of the points containedin a query rectangle) and nearest neighbor search (find aclosest point to a query point).2d-trees have numerous applications, ranging from classifying astronomical objectsto computer animation to speeding up neural networks to mining data to image retrieval.

Range search and k-nearest neighbor


Geometric primitives.To get started, use the following geometric primitives for points andaxis-aligned rectangles in the plane.

Geometric primitives

Use the immutable data type Point2D.java (part of algs4.jar) for points in the plane.Here is the subset of its API that you may use:

public class Point2D implements Comparable<Point2D> {   public Point2D(double x, double y)              // construct the point (x, y)   public double x()                               // x-coordinate   public double y()                               // y-coordinate   public double distanceTo(Point2D that)          // Euclidean distance between two points   public double distanceSquaredTo(Point2D that)   // square of Euclidean distance between two points   public int compareTo(Point2D that)              // for use in an ordered symbol table   public boolean equals(Object that)              // does this point equal that?   public void draw()                              // draw to standard draw   public String toString()                        // string representation}
Use the immutable data type RectHV.java(not part of algs4.jar)for axis-aligned rectanges.Here is the subset of its API that you may use:
public class RectHV {   public RectHV(double xmin, double ymin,         // construct the rectangle [xmin, xmax] x [ymin, ymax]                 double xmax, double ymax)         // throw a java.lang.IllegalArgumentException if (xmin > xmax) or (ymin > ymax)   public double xmin()                            // minimum x-coordinate of rectangle   public double ymin()                            // minimum y-coordinate of rectangle   public double xmax()                            // maximum x-coordinate of rectangle   public double ymax()                            // maximum y-coordinate of rectangle   public boolean contains(Point2D p)              // does this rectangle contain the point p (either inside or on boundary)?   public boolean intersects(RectHV that)          // does this rectangle intersect that rectangle (at one or more points)?   public double distanceTo(Point2D p)             // Euclidean distance from point p to the closest point in rectangle   public double distanceSquaredTo(Point2D p)      // square of Euclidean distance from point p to closest point in rectangle   public boolean equals(Object that)              // does this rectangle equal that?   public void draw()                              // draw to standard draw   public String toString()                        // string representation}
Do not modify these data types.

Brute-force implementation.Write a mutable data type PointSET.java that represents a set ofpoints in the unit square. Implement the following API by using ared-black BST (using eitherSET from algs4.jar or java.util.TreeSet).

public class PointSET {   public PointSET()                               // construct an empty set of points   public boolean isEmpty()                        // is the set empty?   public int size()                               // number of points in the set   public void insert(Point2D p)                   // add the point p to the set (if it is not already in the set)   public boolean contains(Point2D p)              // does the set contain the point p?   public void draw()                              // draw all of the points to standard draw   public Iterable<Point2D> range(RectHV rect)     // all points in the set that are inside the rectangle   public Point2D nearest(Point2D p)               // a nearest neighbor in the set to p; null if set is empty}
Your implementation should support insert() and contains() in timeproportional to the logarithm of the number of points in the set in the worst case; it should supportnearest() andrange() in time proportional to the number of points in the set.

2d-tree implementation.Write a mutable data type KdTree.java that uses a 2d-tree to implement the same API (but replacePointSET with KdTree).A 2d-tree is a generalization of a BST to two-dimensional keys.The idea is to build a BST with points in the nodes,using thex- and y-coordinates of the pointsas keys in strictly alternating sequence.

  • Search and insert. The algorithms for search and insert are similar to those forBSTs, but at the root we use thex-coordinate(if the point to be inserted has a smaller x-coordinatethan the point at the root, go left; otherwise go right);then at the next level, we use they-coordinate(if the point to be inserted has a smaller y-coordinatethan the point in the node, go left; otherwise go right);then at the next level thex-coordinate, and so forth.

Insert (0.7, 0.2)

insert (0.7, 0.2)
Insert (0.5, 0.4)

insert (0.5, 0.4)
Insert (0.2, 0.3)

insert (0.2, 0.3)
Insert (0.4, 0.7)

insert (0.4, 0.7)
Insert (0.9, 0.6)

insert (0.9, 0.6)
Insert (0.7, 0.2)
Insert (0.5, 0.4)
Insert (0.2, 0.3)
Insert (0.4, 0.7)
Insert (0.9, 0.6)
  • Draw. A 2d-tree divides the unit square in a simple way: all the points to theleft of the root go in the left subtree; all those to the right go in the right subtree; and so forth, recursively.Yourdraw() method should draw all of the points to standard drawin black and the subdivisions in red (for vertical splits) and blue (for horizontal splits).This method need not be efficient—it is primarily for debugging.

The prime advantage of a 2d-tree over a BSTis that it supports efficientimplementation of range search and nearest neighbor search.Each node corresponds to an axis-aligned rectangle in the unit square,which encloses all of the points in its subtree.The root corresponds to the unit square; the left and right childrenof the root corresponds to the two rectanglessplit by thex-coordinate of the point at the root; and so forth.

  • Range search.To find all points contained in a given query rectangle, start at the rootand recursively search for points inboth subtrees using the followingpruning rule: if the query rectangle does not intersect the rectangle corresponding to a node, there is no need to explore that node (or its subtrees).A subtree is searched only if it might contain a point contained inthe query rectangle.
  • Nearest neighbor search.To find a closest point to a given query point, start at the rootand recursively search inboth subtrees using the following pruning rule:if the closest point discovered so far is closer than the distance between the query point and the rectangle corresponding to a node,there is no need to explore that node (or its subtrees).That is, a node is searched only if it might contain a pointthat is closer than the best one found so far.The effectiveness of the pruning rule depends on quickly finding a nearby point. To do this, organize your recursive method so that when there are two possible subtrees to go down, you always choose the subtreethat is on the same side of the splitting line as the query pointas the first subtree to explore—the closest pointfound while exploring the firstsubtree may enable pruning of the second subtree.

分析

我们一个一个对题目中的各个元素进行分析。

Point2D

首先是Point2D.java。在Princeton这一课程的网站上面,实际上已经公开了Point2D.java的源代码,大家可以直接使用。我想说的是,Princeton给出的这个代码写的非常规范,源代码的风格值得大家学习。下面是Point2D的源代码。

原始代码链接:http://algs4.cs.princeton.edu/code/Point2D.java.html

/************************************************************************* *  Compilation:  javac Point2D.java * *  Immutable point data type for points in the plane. * *************************************************************************/import java.util.Comparator;/** * The <tt>Point</tt> class is an immutable data type to encapsulate a * two-dimensional point with real-value coordinates. * <p> * Note: in order to deal with the difference behavior of double and Double with * respect to -0.0 and +0.0, the Point2D constructor converts any coordinates * that are -0.0 to +0.0. *  * For additional documentation, see <a href="/algs4/12oop">Section 1.2</a> of * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne. *  * @author Robert Sedgewick * @author Kevin Wayne */public class Point2D implements Comparable<Point2D> {/** * Compares two points by x-coordinate. */public static final Comparator<Point2D> X_ORDER = new XOrder();/** * Compares two points by y-coordinate. */public static final Comparator<Point2D> Y_ORDER = new YOrder();/** * Compares two points by polar radius. */public static final Comparator<Point2D> R_ORDER = new ROrder();/** * Compares two points by polar angle (between 0 and 2pi) with respect to * this point. */public final Comparator<Point2D> POLAR_ORDER = new PolarOrder();/** * Compares two points by atan2() angle (between -pi and pi) with respect to * this point. */public final Comparator<Point2D> ATAN2_ORDER = new Atan2Order();/** * Compares two points by distance to this point. */public final Comparator<Point2D> DISTANCE_TO_ORDER = new DistanceToOrder();private final double x; // x coordinateprivate final double y; // y coordinate/** * Initializes a new point (x, y). *  * @param x *            the x-coordinate * @param y *            the y-coordinate * @throws IllegalArgumentException *             if either <tt>x</tt> or <tt>y</tt> is <tt>Double.NaN</tt>, *             <tt>Double.POSITIVE_INFINITY</tt> or *             <tt>Double.NEGATIVE_INFINITY</tt> */public Point2D(double x, double y) {if (Double.isInfinite(x) || Double.isInfinite(y))throw new IllegalArgumentException("Coordinates must be finite");if (Double.isNaN(x) || Double.isNaN(y))throw new IllegalArgumentException("Coordinates cannot be NaN");if (x == 0.0)x = 0.0; // convert -0.0 to +0.0if (y == 0.0)y = 0.0; // convert -0.0 to +0.0this.x = x;this.y = y;}/** * Returns the x-coordinate. *  * @return the x-coordinate */public double x() {return x;}/** * Returns the y-coordinate. *  * @return the y-coordinate */public double y() {return y;}/** * Returns the polar radius of this point. *  * @return the polar radius of this point in polar coordiantes: sqrt(x*x + *         y*y) */public double r() {return Math.sqrt(x * x + y * y);}/** * Returns the angle of this point in polar coordinates. *  * @return the angle (in radians) of this point in polar coordiantes *         (between -pi/2 and pi/2) */public double theta() {return Math.atan2(y, x);}/** * Returns the angle between this point and that point. *  * @return the angle in radians (between -pi and pi) between this point and *         that point (0 if equal) */private double angleTo(Point2D that) {double dx = that.x - this.x;double dy = that.y - this.y;return Math.atan2(dy, dx);}/** * Is a->b->c a counterclockwise turn? *  * @param a *            first point * @param b *            second point * @param c *            third point * @return { -1, 0, +1 } if a->b->c is a { clockwise, collinear; *         counterclocwise } turn. */public static int ccw(Point2D a, Point2D b, Point2D c) {double area2 = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);if (area2 < 0)return -1;else if (area2 > 0)return +1;elsereturn 0;}/** * Returns twice the signed area of the triangle a-b-c. *  * @param a *            first point * @param b *            second point * @param c *            third point * @return twice the signed area of the triangle a-b-c */public static double area2(Point2D a, Point2D b, Point2D c) {return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);}/** * Returns the Euclidean distance between this point and that point. *  * @param that *            the other point * @return the Euclidean distance between this point and that point */public double distanceTo(Point2D that) {double dx = this.x - that.x;double dy = this.y - that.y;return Math.sqrt(dx * dx + dy * dy);}/** * Returns the square of the Euclidean distance between this point and that * point. *  * @param that *            the other point * @return the square of the Euclidean distance between this point and that *         point */public double distanceSquaredTo(Point2D that) {double dx = this.x - that.x;double dy = this.y - that.y;return dx * dx + dy * dy;}/** * Compares this point to that point by y-coordinate, breaking ties by * x-coordinate. *  * @param that *            the other point * @return { a negative integer, zero, a positive integer } if this point is *         { less than, equal to, greater than } that point */public int compareTo(Point2D that) {if (this.y < that.y)return -1;if (this.y > that.y)return +1;if (this.x < that.x)return -1;if (this.x > that.x)return +1;return 0;}// compare points according to their x-coordinateprivate static class XOrder implements Comparator<Point2D> {public int compare(Point2D p, Point2D q) {if (p.x < q.x)return -1;if (p.x > q.x)return +1;return 0;}}// compare points according to their y-coordinateprivate static class YOrder implements Comparator<Point2D> {public int compare(Point2D p, Point2D q) {if (p.y < q.y)return -1;if (p.y > q.y)return +1;return 0;}}// compare points according to their polar radiusprivate static class ROrder implements Comparator<Point2D> {public int compare(Point2D p, Point2D q) {double delta = (p.x * p.x + p.y * p.y) - (q.x * q.x + q.y * q.y);if (delta < 0)return -1;if (delta > 0)return +1;return 0;}}// compare other points relative to atan2 angle (bewteen -pi/2 and pi/2)// they make with this Pointprivate class Atan2Order implements Comparator<Point2D> {public int compare(Point2D q1, Point2D q2) {double angle1 = angleTo(q1);double angle2 = angleTo(q2);if (angle1 < angle2)return -1;else if (angle1 > angle2)return +1;elsereturn 0;}}// compare other points relative to polar angle (between 0 and 2pi) they// make with this Pointprivate class PolarOrder implements Comparator<Point2D> {public int compare(Point2D q1, Point2D q2) {double dx1 = q1.x - x;double dy1 = q1.y - y;double dx2 = q2.x - x;double dy2 = q2.y - y;if (dy1 >= 0 && dy2 < 0)return -1; // q1 above; q2 belowelse if (dy2 >= 0 && dy1 < 0)return +1; // q1 below; q2 aboveelse if (dy1 == 0 && dy2 == 0) { // 3-collinear and horizontalif (dx1 >= 0 && dx2 < 0)return -1;else if (dx2 >= 0 && dx1 < 0)return +1;elsereturn 0;} elsereturn -ccw(Point2D.this, q1, q2); // both above or below// Note: ccw() recomputes dx1, dy1, dx2, and dy2}}// compare points according to their distance to this pointprivate class DistanceToOrder implements Comparator<Point2D> {public int compare(Point2D p, Point2D q) {double dist1 = distanceSquaredTo(p);double dist2 = distanceSquaredTo(q);if (dist1 < dist2)return -1;else if (dist1 > dist2)return +1;elsereturn 0;}}/** * Does this point equal y? *  * @param other *            the other point * @return true if this point equals the other point; false otherwise */public boolean equals(Object other) {if (other == this)return true;if (other == null)return false;if (other.getClass() != this.getClass())return false;Point2D that = (Point2D) other;return this.x == that.x && this.y == that.y;}/** * Return a string representation of this point. *  * @return a string representation of this point in the format (x, y) */public String toString() {return "(" + x + ", " + y + ")";}/** * Returns an integer hash code for this point. *  * @return an integer hash code for this point */public int hashCode() {int hashX = ((Double) x).hashCode();int hashY = ((Double) y).hashCode();return 31 * hashX + hashY;}/** * Plot this point using standard draw. */public void draw() {StdDraw.point(x, y);}/** * Plot a line from this point to that point using standard draw. *  * @param that *            the other point */public void drawTo(Point2D that) {StdDraw.line(this.x, this.y, that.x, that.y);}}

RectHV

刚开始我还以为Princeton没有实现这一类的代码呢,自己辛辛苦苦地写了一遍,然后发现代码已经给出来了… 不过在此也可以跟大家分享一下实现RectHV.java的一些心得。RectHV.java中,其他都好说,用TreeSet类的功能基本都能够实现。唯一需要注意的就是interset这个函数,也就是说,如何判断两个矩形是重叠的。在公开课上面,对此已经进行了讲解。在此我们引用其他网友的一个博客来更形象的说明这一个问题。原文链接为:http://blog.sina.com.cn/s/blog_ab20767501017n1x.html。

如果我们假设矩形是由左下角的点和右上角的点表示的,即一个矩形可以用Point2D(xmin, ymin)和Point2D(xmax, ymax)表示的话。同时,假设2个矩形的左下和右上分别为 (x1,y1), (x2,y2) 和 (x3,y3), (x4,y4)那么,两个矩形碰撞,则且仅当:

(x4 > x1 && y4 > y1 && x3 < x2 && y3 < y2)


 HDU <wbr> <wbr>2056 <wbr> <wbr>(矩形重叠)Rectangles

即:矩形B的右上点大于矩形A的左下点,并且矩形B的左下点小于矩形A的右上点。
下面是RectHV的源代码。原始代码链接:http://algs4.cs.princeton.edu/code/RectHV.java.html。
/************************************************************************* * Compilation: javac RectHV.java Execution: java RectHV Dependencies: * Point2D.java *  * Implementation of 2D axis-aligned rectangle. *  *************************************************************************/public class RectHV {private final double xmin, ymin; // minimum x- and y-coordinatesprivate final double xmax, ymax; // maximum x- and y-coordinates// construct the axis-aligned rectangle [xmin, xmax] x [ymin, ymax]public RectHV(double xmin, double ymin, double xmax, double ymax) {if (xmax < xmin || ymax < ymin) {throw new IllegalArgumentException("Invalid rectangle");}this.xmin = xmin;this.ymin = ymin;this.xmax = xmax;this.ymax = ymax;}// accessor methods for 4 coordinatespublic double xmin() {return xmin;}public double ymin() {return ymin;}public double xmax() {return xmax;}public double ymax() {return ymax;}// width and height of rectanglepublic double width() {return xmax - xmin;}public double height() {return ymax - ymin;}// does this axis-aligned rectangle intersect that one?public boolean intersects(RectHV that) {return this.xmax >= that.xmin && this.ymax >= that.ymin&& that.xmax >= this.xmin && that.ymax >= this.ymin;}// draw this axis-aligned rectanglepublic void draw() {StdDraw.line(xmin, ymin, xmax, ymin);StdDraw.line(xmax, ymin, xmax, ymax);StdDraw.line(xmax, ymax, xmin, ymax);StdDraw.line(xmin, ymax, xmin, ymin);}// distance from p to closest point on this axis-aligned rectanglepublic double distanceTo(Point2D p) {return Math.sqrt(this.distanceSquaredTo(p));}// distance squared from p to closest point on this axis-aligned rectanglepublic double distanceSquaredTo(Point2D p) {double dx = 0.0, dy = 0.0;if (p.x() < xmin)dx = p.x() - xmin;else if (p.x() > xmax)dx = p.x() - xmax;if (p.y() < ymin)dy = p.y() - ymin;else if (p.y() > ymax)dy = p.y() - ymax;return dx * dx + dy * dy;}// does this axis-aligned rectangle contain p?public boolean contains(Point2D p) {return (p.x() >= xmin) && (p.x() <= xmax) && (p.y() >= ymin)&& (p.y() <= ymax);}// are the two axis-aligned rectangles equal?public boolean equals(Object y) {if (y == this)return true;if (y == null)return false;if (y.getClass() != this.getClass())return false;RectHV that = (RectHV) y;if (this.xmin != that.xmin)return false;if (this.ymin != that.ymin)return false;if (this.xmax != that.xmax)return false;if (this.ymax != that.ymax)return false;return true;}// return a string representation of this axis-aligned rectanglepublic String toString() {return "[" + xmin + ", " + xmax + "] x [" + ymin + ", " + ymax + "]";}}

PointSET

蛮力搜索法对问题进行求解是一种很直接的方法。由于SET(或者TreeSET)插入的计算复杂度为O(log n),搜索复杂度为O(log n)遍历的计算复杂度为O(n),因此我们很容易用代码实现题目中所要求的:insert复杂度为log级,contain复杂度为log级,range复杂度为n级。这实际上是SET(或者TreeSET)带给我们的便利,当然了,这也是数据结构平凡降低算法复杂度的一种很经典的实例。
由于代码非常简单,我就直接把我写的放在下面了。

import java.util.TreeSet;public class PointSET {private TreeSet<Point2D> pointSET;    // construct an empty set of pointspublic PointSET(){this.pointSET = new TreeSet<Point2D>();}    // is the set empty?public boolean isEmpty(){return this.pointSET.size() == 0;}    // number of points in the setpublic int size(){return this.pointSET.size();}    // add the point p to the set (if it is not already in the set)public void insert(Point2D p){pointSET.add(p);}    // does the set contain the point p?public boolean contains(Point2D p){return pointSET.contains(p);}    // draw all of the points to standard drawpublic void draw(){for (Point2D p : pointSET) {            StdDraw.point(p.x(), p.y());        }}    // all points in the set that are inside the rectanglepublic Iterable<Point2D> range(RectHV rect){TreeSet<Point2D> rangeSet = new TreeSet<Point2D>();for (Point2D p : pointSET) {            if (rect.contains(p)){            rangeSet.add(p);            }        }return rangeSet;}    // a nearest neighbor in the set to p; null if set is emptypublic Point2D nearest(Point2D p){Point2D nearestPoint2D = null;double distance = Double.MAX_VALUE;if (this.pointSET.isEmpty()){return nearestPoint2D;}for (Point2D pointIter : pointSET) {            if (pointIter.distanceTo(p) < distance){            nearestPoint2D = pointIter;            distance = pointIter.distanceTo(p);            }        }return nearestPoint2D;}}

KdTree

KdTree方法主要麻烦的地方有如下几点:

1、insert函数中,如何判断我现在插入的节点到底应该用水平排序插入还是应该用垂直排序插入?我们在每一个KdNode加一个参数:isVertical。首先,我们知道第一个点肯定是垂直排序插入的,即RootNode.isVertical = true。那么,其左右节点插入时,isVertical都为!parent.isVertical。这样叠代插入,就能够完成insert的动作了。


2、contain函数的遍历方法?根据算法描述,从rootNode开始进行对比。

(0)如果KdNode中的x和y都和被查找节点相同,则KdTree中包含此节点,返回true。

(1)如果KdNode是垂直的(isVertical == true),因此比较x坐标,如果小于节点的x,则查找在左子树;如果大于节点的x,则查找右子树。随后,叠代查找左(右)节点。

(2)如果KdNode是水平的(isVertical == false),那么比较y坐标,如果小于节点的y,则查找左子树;如果大于节点的y,则查找右子树。随后,叠代查找左(右)节点。

(3)如果子树是空,则KdTree不包含此节点,返回false。

这么一整理,算法就清楚了。也就是说,如果KdTree本身能正确构造,contain函数应用这一算法就能够很容易实现。


3、nearest函数的搜索算法?同理,算法也比较清晰,和contain差不多,但是需要增加一个候选点:如果搜索到的点比候选点更近,则更新候选点;如果搜索到的点比候选点远,则继续进行搜索。直到把搜索树搜索完毕。这种搜索算法有点像A*搜索法,不过在搜索过程中由于KdTree的巧妙构造,每次搜索几乎排除了一半的不可能解,因此提高了搜索的效率。


KdTree的源代码如下,请大家参考。

import java.util.TreeSet;public class KdTree {private static class KdNode {private KdNode leftNode;private KdNode rightNode;private final boolean isVertical;private final double x;private final double y;public KdNode(final double x, final double y, final KdNode leftNode,final KdNode rightNode, final boolean isVertical) {this.x = x;this.y = y;this.leftNode = leftNode;this.rightNode = rightNode;this.isVertical = isVertical;}}private static final RectHV CONTAINER = new RectHV(0, 0, 1, 1);private KdNode rootNode;private int size;// construct an empty set of pointspublic KdTree() {this.size = 0;this.rootNode = null;}// is the set empty?public boolean isEmpty() {return this.size == 0;}// number of points in the setpublic int size() {return this.size;}// add the point p to the set (if it is not already in the set)public void insert(final Point2D p) {this.rootNode = insert(this.rootNode, p, true);}private KdNode insert(final KdNode node, final Point2D p,final boolean isVertical) {// if new node, create itif (node == null) {size++;return new KdNode(p.x(), p.y(), null, null, isVertical);}// if already in, return itif (node.x == p.x() && node.y == p.y()) {return node;}// insert it where corresponds (left - right recursive call)if (node.isVertical && p.x() < node.x || !node.isVertical&& p.y() < node.y) {node.leftNode = insert(node.leftNode, p, !node.isVertical);} else {node.rightNode = insert(node.rightNode, p, !node.isVertical);}return node;}// does the set contain the point p?public boolean contains(Point2D p) {return contains(rootNode, p.x(), p.y());}private boolean contains(KdNode node, double x, double y) {if (node == null) {return false;}if (node.x == x && node.y == y) {return true;}if (node.isVertical && x < node.x || !node.isVertical && y < node.y) {return contains(node.leftNode, x, y);} else {return contains(node.rightNode, x, y);}}// draw all of the points to standard drawpublic void draw() {StdDraw.setScale(0, 1);StdDraw.setPenColor(StdDraw.BLACK);StdDraw.setPenRadius();CONTAINER.draw();draw(rootNode, CONTAINER);}private void draw(final KdNode node, final RectHV rect) {if (node == null) {return;}// draw the pointStdDraw.setPenColor(StdDraw.BLACK);StdDraw.setPenRadius(0.01);new Point2D(node.x, node.y).draw();// get the min and max points of division linePoint2D min, max;if (node.isVertical) {StdDraw.setPenColor(StdDraw.RED);min = new Point2D(node.x, rect.ymin());max = new Point2D(node.x, rect.ymax());} else {StdDraw.setPenColor(StdDraw.BLUE);min = new Point2D(rect.xmin(), node.y);max = new Point2D(rect.xmax(), node.y);}// draw that division lineStdDraw.setPenRadius();min.drawTo(max);// recursively draw childrendraw(node.leftNode, leftRect(rect, node));draw(node.rightNode, rightRect(rect, node));}private RectHV leftRect(final RectHV rect, final KdNode node) {if (node.isVertical) {return new RectHV(rect.xmin(), rect.ymin(), node.x, rect.ymax());} else {return new RectHV(rect.xmin(), rect.ymin(), rect.xmax(), node.y);}}private RectHV rightRect(final RectHV rect, final KdNode node) {if (node.isVertical) {return new RectHV(node.x, rect.ymin(), rect.xmax(), rect.ymax());} else {return new RectHV(rect.xmin(), node.y, rect.xmax(), rect.ymax());}}// all points in the set that are inside the rectanglepublic Iterable<Point2D> range(final RectHV rect) {final TreeSet<Point2D> rangeSet = new TreeSet<Point2D>();range(rootNode, CONTAINER, rect, rangeSet);return rangeSet;}private void range(final KdNode node, final RectHV nrect,final RectHV rect, final TreeSet<Point2D> rangeSet) {if (node == null)return;if (rect.intersects(nrect)) {final Point2D p = new Point2D(node.x, node.y);if (rect.contains(p))rangeSet.add(p);range(node.leftNode, leftRect(nrect, node), rect, rangeSet);range(node.rightNode, rightRect(nrect, node), rect, rangeSet);}}// a nearest neighbor in the set to p; null if set is emptypublic Point2D nearest(final Point2D p) {return nearest(rootNode, CONTAINER, p.x(), p.y(), null);}private Point2D nearest(final KdNode node, final RectHV rect,final double x, final double y, final Point2D candidate) {if (node == null){return candidate;}double dqn = 0.0;double drq = 0.0;RectHV left = null;RectHV rigt = null;final Point2D query = new Point2D(x, y);Point2D nearest = candidate;if (nearest != null) {dqn = query.distanceSquaredTo(nearest);drq = rect.distanceSquaredTo(query);}if (nearest == null || dqn > drq) {final Point2D point = new Point2D(node.x, node.y);if (nearest == null || dqn > query.distanceSquaredTo(point))nearest = point;if (node.isVertical) {left = new RectHV(rect.xmin(), rect.ymin(), node.x, rect.ymax());rigt = new RectHV(node.x, rect.ymin(), rect.xmax(), rect.ymax());if (x < node.x) {nearest = nearest(node.leftNode, left, x, y, nearest);nearest = nearest(node.rightNode, rigt, x, y, nearest);} else {nearest = nearest(node.rightNode, rigt, x, y, nearest);nearest = nearest(node.leftNode, left, x, y, nearest);}} else {left = new RectHV(rect.xmin(), rect.ymin(), rect.xmax(), node.y);rigt = new RectHV(rect.xmin(), node.y, rect.xmax(), rect.ymax());if (y < node.y) {nearest = nearest(node.leftNode, left, x, y, nearest);nearest = nearest(node.rightNode, rigt, x, y, nearest);} else {nearest = nearest(node.rightNode, rigt, x, y, nearest);nearest = nearest(node.leftNode, left, x, y, nearest);}}}return nearest;}}

后记

至此,Princeton的《Algorithm Part I》的所有Assignments就都做完了。对于知识本身来说,我必须承认国内的计算机教学确实落后了最好学校一大截。大家可以仔细看看Princeton的代码评价平台,非常的完备,整个report非常详尽,给出了几乎可能给出的所有信息。如果国内也有这样的平台,那是再好不过的了。但是,这样平台的搭建本身就需要深厚的技术功底,并且对于Java虚拟机等运作方式非常了解。而开发这样的平台本身对于科研是没有帮助的… 因此,本质上说,国内高校的老师们仍然更偏重于自己的项目,而较为忽略教学。即使有个别老师热衷于教学,但由于本身代码水平有限,也没有足够的时间开发这样的平台;如果这位老师代码水平较高,其科研和开发任务相对也就更重,时间就无法保证了。可以这么说,如果我自己毕业后留在学校任教,我可能也不会花费大量的心思开发这样的平台供学生使用。

本质上说,高校的开发能力肯定没有企业强。因此,从根源上说,还是国内高校和企业需求脱离的太厉害了。如果学校的学生能在学校的同时和各个知名企业进行交流,我想即使本科生们也可以在学校和企业的共同指导下,在短时间内开发出既满足高校需求,又锻炼自身开发能力的类似这样的平台。

总的来说,慢慢来吧!我想,既然能出现像我这样略神经的学生,今后肯定还会有更多这样的学生来逐步完善国内高校教育,特别是计算机科学教育的实验平台。大家一起努力喽!

1 0
原创粉丝点击