First commit

master
En Yi 2019-08-30 14:58:22 +08:00
commit 7f5a224a40
18 changed files with 2351 additions and 0 deletions

5
.gitignore vendored 100644
View File

@ -0,0 +1,5 @@
Week*/*
!.gitignore
!Week*/src/
*.zip
*.jar

View File

@ -0,0 +1,124 @@
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
import edu.princeton.cs.algs4.StdRandom;
public class Percolation {
private boolean[][] grid;
private int size;
private WeightedQuickUnionUF grid_uf;
private WeightedQuickUnionUF grid_uf_2; //This is to check for isFull to prevent backwash
private int n_open_sites;
private int end_site;
// creates n-by-n grid, with all sites initially blocked
public Percolation(int n){
if (n<=0){
throw new IllegalArgumentException("Invalid size: " + n);
}
grid = new boolean[n][n];
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
grid[i][j] = false;
}
}
size = n;
grid_uf = new WeightedQuickUnionUF(n*n+2); // Need extra 2 virtual sites
grid_uf_2 = new WeightedQuickUnionUF(n*n+1); // Need extra 1 virtual sites
end_site = n*n+1;
}
// opens the site (row, col) if it is not open already
public void open(int row, int col){
if (row<=0 || row>size || col<=0 || col>size){
throw new IllegalArgumentException("Invalid row and col values: (" + row + ", " + col + ")");
}
if (!isOpen(row, col)){
grid[row-1][col-1] = true;
n_open_sites++;
int index = col + (row - 1) * size;
if (row == 1){
grid_uf.union(0, index);
grid_uf_2.union(0, index);
}
if (row == size){
grid_uf.union(end_site, index);
}
// Check up
if(row>1 && isOpen(row-1, col)){
grid_uf.union(index - size, index);
grid_uf_2.union(index - size, index);
}
// Check down
if(row<size && isOpen(row+1, col)){
grid_uf.union(index + size, index);
grid_uf_2.union(index + size, index);
}
// Check left
if(col>1 && isOpen(row, col-1)){
grid_uf.union(index-1, index);
grid_uf_2.union(index-1, index);
}
// Check right
if(col<size && isOpen(row, col+1)){
grid_uf.union(index+1, index);
grid_uf_2.union(index+1, index);
}
}
}
// is the site (row, col) open?
public boolean isOpen(int row, int col){
if (row<=0 || row>size || col<=0 || col>size){
throw new IllegalArgumentException("Invalid row and col values: (" + row + ", " + col + ")");
}
return grid[row-1][col-1];
}
// is the site (row, col) full?
public boolean isFull(int row, int col){
if (row<=0 || row>size || col<=0 || col>size){
throw new IllegalArgumentException("Invalid row and col values: (" + row + ", " + col + ")");
}
return grid_uf_2.connected(0, col + (row - 1) * size);
}
// returns the number of open sites
public int numberOfOpenSites(){
return n_open_sites;
}
// does the system percolate?
public boolean percolates(){
return grid_uf.connected(0, end_site);
}
// test client (optional)
public static void main(String[] args){
int n = 8;
Percolation grid = new Percolation(n);
int row, col;
while(!grid.percolates()){
row = StdRandom.uniform(1, n+1);
col = StdRandom.uniform(1, n+1);
System.out.print(row);
System.out.println(" " + col);
grid.open(row, col);
}
System.out.println(grid.numberOfOpenSites());
System.out.println((double)grid.numberOfOpenSites()/(n*n));
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if (grid.isFull(i, j))
System.out.printf("%1s", 2);
else
System.out.printf("%1s", grid.isOpen(i, j)?1:0);
}
System.out.println("");
}
}
}

View File

@ -0,0 +1,78 @@
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
//import edu.princeton.cs.algs4.Stopwatch;
public class PercolationStats {
private int trials;
private double results_mean;
private double results_stddev;
// perform independent trials on an n-by-n grid
public PercolationStats(int n, int trials){
if (n<=0 || trials<=0){
throw new IllegalArgumentException("n and trials should be non-zero: (" + n + " " + trials + ")");
}
this.trials = trials;
double[] trial_results = new double[trials];
Percolation grid;
for (int i=0;i<trials; i++){
grid = new Percolation(n);
int row, col;
while(!grid.percolates()){
row = StdRandom.uniform(1, n+1);
col = StdRandom.uniform(1, n+1);
grid.open(row, col);
}
trial_results[i] = (double)grid.numberOfOpenSites()/(n*n);
}
results_mean = StdStats.mean(trial_results);
results_stddev = StdStats.stddev(trial_results);
}
// sample mean of percolation threshold
public double mean(){
return results_mean;
}
// sample standard deviation of percolation threshold
public double stddev(){
return results_stddev;
}
// low endpoint of 95% confidence interval
public double confidenceLo(){
double error = 1.96 * results_stddev / Math.sqrt(trials);
return results_mean - error;
}
// high endpoint of 95% confidence interval
public double confidenceHi(){
double error = 1.96 * results_stddev / Math.sqrt(trials);
return results_mean + error;
}
// test client (see below)
public static void main(String[] args){
if (!(args.length == 2)){
throw new IllegalArgumentException("Only 2 arguments are required");
}
int n, trials;
try{
n = Integer.parseInt(args[0]);
trials = Integer.parseInt(args[1]);
}catch(NumberFormatException e){
System.out.println("Please give integers as inputs.");
throw(e);
}
//Stopwatch clock = new Stopwatch();
PercolationStats percol_stats = new PercolationStats(n, trials);
//System.out.printf("%-45s = %.20f\n", "Time elapsed", clock.elapsedTime());
System.out.printf("%-45s = %.20f\n", "mean", percol_stats.mean());
System.out.printf("%-45s = %.20f\n", "stddev", percol_stats.stddev());
System.out.printf("%-45s = [%.20f, %.20f]\n", "95%% confidence interval", percol_stats.confidenceLo(), percol_stats.confidenceHi());
}
}

View File

@ -0,0 +1,161 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Deque<Item> implements Iterable<Item>{
private class Node{
Item item;
Node next;
Node prev;
}
private Node first = null;
private Node last = null;
private int length = 0;
// construct an empty deque
public Deque(){
}
// is the deque empty?
public boolean isEmpty(){
return (length == 0);
}
// return the number of items on the deque
public int size(){
return length;
}
// add the item to the front
public void addFirst(Item item){
if (item == null){
throw new IllegalArgumentException("Null item is not accepted.");
}
Node new_node = new Node();
new_node.item = item;
new_node.next = first;
new_node.prev = null;
if (first == null){
last = new_node;
}else{
first.prev = new_node;
}
first = new_node;
length++;
}
// add the item to the back
public void addLast(Item item){
if (item == null){
throw new IllegalArgumentException("Null item is not accepted.");
}
Node new_node = new Node();
new_node.item = item;
new_node.next = null;
new_node.prev = last;
if (last == null){
first = new_node;
}else{
last.next = new_node;
}
last = new_node;
length++;
}
// remove and return the item from the front
public Item removeFirst(){
if (isEmpty()){
throw new NoSuchElementException("Queue is empty.");
}
Item item = first.item;
first = first.next;
if(first != null){
first.prev = null;
}
length--;
if(first == null){
last = null;
}
return item;
}
// remove and return the item from the back
public Item removeLast(){
if (isEmpty()){
throw new NoSuchElementException("Queue is empty.");
}
Item item = last.item;
if (length == 1){
first = null;
last = null;
}else{
last = last.prev;
last.next = null;
}
length--;
return item;
}
// return an iterator over items in order from front to back
public Iterator<Item> iterator(){
return new dequeIterator();
}
private class dequeIterator implements Iterator<Item>{
private Node current = first;
public boolean hasNext(){
return current != null;
}
public void remove(){
throw new UnsupportedOperationException("Remove operation is not supported.");
}
public Item next(){
if (!hasNext()){
throw new NoSuchElementException("No next item.");
}
Item item = current.item;
current = current.next;
return item;
}
}
// unit testing (required)
public static void main(String[] args){
Deque<Integer> test_deque = new Deque<Integer>();
System.out.println(test_deque.isEmpty());
test_deque.addFirst(2);
test_deque.addLast(5);
System.out.println(test_deque.removeLast());
System.out.println(test_deque.removeFirst());
test_deque.addFirst(1);
test_deque.addFirst(2);
test_deque.addFirst(3);
test_deque.addFirst(4);
test_deque.removeLast();
test_deque.addFirst(3);
test_deque.addFirst(7);
test_deque.addFirst(9);
test_deque.addLast(13);
test_deque.addLast(19);
test_deque.addLast(1);
System.out.println("Size: " + test_deque.size());
Iterator<Integer> iter = test_deque.iterator();
while(iter.hasNext()){
System.out.print(iter.next());
System.out.print(" ");
}
System.out.println("");
}
}

View File

@ -0,0 +1,49 @@
import java.util.Iterator;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdRandom;
public class Permutation {
public static void main(String[] args){
if (args.length < 1){
throw new IllegalArgumentException("Only 1 argument is required");
}
int k = Integer.parseInt(args[0]);
/*RandomizedQueue<String> queue = new RandomizedQueue<String>();
while(!StdIn.isEmpty()){
queue.enqueue(StdIn.readString());
}
Iterator<String> iter = queue.iterator();
for (int i=0;i<k;i++){
if (iter.hasNext()){
System.out.println(iter.next());
}
}*/
if (k >0){
RandomizedQueue<String> queue = new RandomizedQueue<String>();
String str;
int n = 0;
while(!StdIn.isEmpty()){
str = StdIn.readString();
n++;
if (queue.size() < k){
queue.enqueue(str);
}else{
int i = StdRandom.uniform(1, n+1);
if (i <= k){
queue.dequeue();
queue.enqueue(str);
}
}
}
Iterator<String> iter = queue.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
}
}
}
}

View File

@ -0,0 +1,135 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdRandom;
public class RandomizedQueue<Item> implements Iterable<Item> {
private Item[] queue;
private int length = 0;
// construct an empty randomized queue
public RandomizedQueue(){
queue = (Item[]) new Object[1];
}
// is the randomized queue empty?
public boolean isEmpty(){
return (length == 0);
}
// return the number of items on the randomized queue
public int size(){
return length;
}
// add the item
public void enqueue(Item item){
if (item == null){
throw new IllegalArgumentException("Null item is not accepted.");
}
if (length == queue.length){
resize(2 * queue.length);
}
queue[length++] = item;
}
// remove and return a random item
public Item dequeue(){
if (isEmpty()){
throw new NoSuchElementException("Queue is empty.");
}
int index = StdRandom.uniform(0, length);
Item item = queue[index];
queue[index] = queue[length-1];
queue[--length] = null;
if (length > 0 && length == queue.length/4){
resize(queue.length/2);
}
return item;
}
// return a random item (but do not remove it)
public Item sample(){
if (isEmpty()){
throw new NoSuchElementException("Queue is empty.");
}
return queue[StdRandom.uniform(0, length)];
}
private void resize(int capacity) {
Item[] copy = (Item[]) new Object[capacity];
for (int i = 0; i < length; i++){
copy[i] = queue[i];
}
queue = copy;
}
// return an independent iterator over items in random order
public Iterator<Item> iterator(){
return new queueIterator();
}
private class queueIterator implements Iterator<Item>{
private int current = 0;
private Item[] iter_list;
private queueIterator(){
iter_list = (Item[]) new Object[length];
for (int i = 0; i < length; i++){
iter_list[i] = queue[i];
}
StdRandom.shuffle(iter_list);
}
public boolean hasNext(){
return current != iter_list.length;
}
public void remove(){
throw new UnsupportedOperationException("Remove operation is not supported.");
}
public Item next(){
if (!hasNext()){
throw new NoSuchElementException("No next item.");
}
return iter_list[current++];
}
}
// unit testing (required)
public static void main(String[] args){
RandomizedQueue<Integer> test_deque = new RandomizedQueue<Integer>();
System.out.println(test_deque.isEmpty());
test_deque.enqueue(2);
test_deque.enqueue(3);
System.out.println("Size: "+test_deque.size());
System.out.println(test_deque.dequeue());
System.out.println(test_deque.dequeue());
for(int i=0;i<10;i++){
test_deque.enqueue(i);
}
System.out.println("Size: "+test_deque.size());
System.out.println(test_deque.sample());
System.out.println(test_deque.sample());
Iterator<Integer> iter = test_deque.iterator();
Iterator<Integer> iter2 = test_deque.iterator();
while(iter.hasNext()){
System.out.print(iter.next());
System.out.print(" ");
}
System.out.println("");
while(iter2.hasNext()){
System.out.print(iter2.next());
System.out.print(" ");
}
System.out.println("");
}
}

View File

@ -0,0 +1,81 @@
import java.util.Arrays;
public class BruteCollinearPoints {
private int num_of_segments;
private LineSegment[] line_segments;
// finds all line segments containing 4 points
public BruteCollinearPoints(Point[] points){
if (points == null){
throw new IllegalArgumentException("Points cannot be null.");
}
for(int i=0; i<points.length;i++){
if (points[i] == null){
throw new IllegalArgumentException("No null points allowed.");
}
}
Point[] original_copy = (Point[]) points.clone();
Arrays.sort(original_copy);
for(int i=0; i<original_copy.length-1;i++){
if (original_copy[i].compareTo(original_copy[i+1]) == 0){
throw new IllegalArgumentException("No duplicate points allowed.");
}
}
line_segments = new LineSegment[1];
num_of_segments = 0;
int p, q, r, s;
double s1;
if(original_copy.length >=4){
for(p=0;p<=original_copy.length-4;p++){
for(q=p+1;q<=original_copy.length-3;q++){
s1 = original_copy[p].slopeTo(original_copy[q]);
for(r=q+1;r<=original_copy.length-2;r++){
if (original_copy[p].slopeTo(original_copy[r]) != s1)
continue;
for(s=r+1;s<=original_copy.length-1;s++){
if (original_copy[p].slopeTo(original_copy[s]) != s1)
continue;
if (num_of_segments == line_segments.length){
resize(2*num_of_segments);
}
line_segments[num_of_segments++] = new LineSegment(original_copy[p], original_copy[s]);
}
}
}
}
if (num_of_segments > 0)
resize(num_of_segments);
}
}
// the number of line segments
public int numberOfSegments(){
return num_of_segments;
}
// the line segments
public LineSegment[] segments(){
LineSegment[] return_array= new LineSegment[num_of_segments];
for (int i=0;i<num_of_segments;i++)
return_array[i] = line_segments[i];
return return_array;
}
private void resize(int capacity){
LineSegment[] copy = new LineSegment[capacity];
for (int i = 0; i < num_of_segments; i++){
copy[i] = line_segments[i];
}
line_segments = copy;
}
}

View File

@ -0,0 +1,118 @@
import java.util.Arrays;
public class FastCollinearPoints {
private int num_of_segments;
private LineSegment[] line_segments;
// finds all line segments containing 4 points
public FastCollinearPoints(Point[] points){
if (points == null){
throw new IllegalArgumentException("Points cannot be null.");
}
for(int i=0; i<points.length;i++){
if (points[i] == null){
throw new IllegalArgumentException("No null points allowed.");
}
}
Point[] original_copy = (Point[]) points.clone();
Arrays.sort(original_copy);
for(int i=0; i<original_copy.length-1;i++){
if (original_copy[i].compareTo(original_copy[i+1]) == 0){
throw new IllegalArgumentException("No duplicate points allowed.");
}
}
int est_segments = points.length / 2 + 1;
line_segments = new LineSegment[est_segments];
num_of_segments = 0;
Point[] segments_start_points = new Point[est_segments];
double[] segments_slopes = new double[est_segments];
int n_connected = 1;
double current_slope = 0;
int p, q;
double s1;
if(original_copy.length >=4){
for(p=0;p<=original_copy.length-4;p++){
Point[] points_copy = new Point[original_copy.length-p];
for(int i=p;i<original_copy.length;i++){
points_copy[i-p] = original_copy[i];
}
Arrays.sort(points_copy, original_copy[p].slopeOrder());
current_slope = Double.NEGATIVE_INFINITY;
for(q=1;q<points_copy.length;q++){
s1 = points_copy[0].slopeTo(points_copy[q]);
boolean check_needed = false;
int offset = 1;
if (s1 == current_slope){
n_connected++;
if (q==points_copy.length-1){
check_needed = true;
offset = 0;
}
}else{
check_needed = true;
}
if (check_needed){
if(n_connected >= 4){
boolean dupe = false;
if (num_of_segments>0){
for (int i=0;i<num_of_segments;i++){
if (current_slope == segments_slopes[i] &&
points_copy[0].slopeTo(segments_start_points[i]) == segments_slopes[i]) {
dupe = true;
break;
}
}
}
if (!dupe){
if (num_of_segments == line_segments.length){
resize(2*num_of_segments);
Point[] copy2 = new Point[2*num_of_segments];
double[] copy3 = new double[2*num_of_segments];
for (int i = 0; i < num_of_segments; i++){
copy2[i] = segments_start_points[i];
copy3[i] = segments_slopes[i];
}
segments_start_points = copy2;
segments_slopes = copy3;
}
line_segments[num_of_segments] = new LineSegment(points_copy[0], points_copy[q-offset]);
segments_start_points[num_of_segments] = points_copy[0];
segments_slopes[num_of_segments++] = current_slope;
}
}
n_connected = 2;
current_slope = s1;
}
}
}
resize(num_of_segments);
}
}
// the number of line segments
public int numberOfSegments(){
return num_of_segments;
}
// the line segments
public LineSegment[] segments(){
return (LineSegment[]) line_segments.clone();
}
private void resize(int capacity){
LineSegment[] copy = new LineSegment[capacity];
for (int i = 0; i < num_of_segments; i++){
copy[i] = line_segments[i];
}
line_segments = copy;
}
}

View File

@ -0,0 +1,65 @@
/*************************************************************************
* Compilation: javac LineSegment.java
* Execution: none
* Dependencies: Point.java
*
* An immutable data type for Line segments in the plane.
* For use on Coursera, Algorithms Part I programming assignment.
*
* DO NOT MODIFY THIS CODE.
*
*************************************************************************/
public class LineSegment {
private final Point p; // one endpoint of this line segment
private final Point q; // the other endpoint of this line segment
/**
* Initializes a new line segment.
*
* @param p one endpoint
* @param q the other endpoint
* @throws NullPointerException if either <tt>p</tt> or <tt>q</tt>
* is <tt>null</tt>
*/
public LineSegment(Point p, Point q) {
if (p == null || q == null) {
throw new NullPointerException("argument is null");
}
this.p = p;
this.q = q;
}
/**
* Draws this line segment to standard draw.
*/
public void draw() {
p.drawTo(q);
}
/**
* Returns a string representation of this line segment
* This method is provide for debugging;
* your program should not rely on the format of the string representation.
*
* @return a string representation of this line segment
*/
public String toString() {
return p + " -> " + q;
}
/**
* Throws an exception if called. The hashCode() method is not supported because
* hashing has not yet been introduced in this course. Moreover, hashing does not
* typically lead to good *worst-case* performance guarantees, as required on this
* assignment.
*
* @throws UnsupportedOperationException if called
*/
public int hashCode() {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,154 @@
/******************************************************************************
* Compilation: javac Point.java
* Execution: java Point
* Dependencies: none
*
* An immutable data type for points in the plane.
* For use on Coursera, Algorithms Part I programming assignment.
*
******************************************************************************/
import java.util.Comparator;
import edu.princeton.cs.algs4.StdDraw;
public class Point implements Comparable<Point> {
private final int x; // x-coordinate of this point
private final int y; // y-coordinate of this point
/**
* Initializes a new point.
*
* @param x the <em>x</em>-coordinate of the point
* @param y the <em>y</em>-coordinate of the point
*/
public Point(int x, int y) {
/* DO NOT MODIFY */
this.x = x;
this.y = y;
}
/**
* Draws this point to standard draw.
*/
public void draw() {
/* DO NOT MODIFY */
StdDraw.point(x, y);
}
/**
* Draws the line segment between this point and the specified point
* to standard draw.
*
* @param that the other point
*/
public void drawTo(Point that) {
/* DO NOT MODIFY */
StdDraw.line(this.x, this.y, that.x, that.y);
}
/**
* Returns the slope between this point and the specified point.
* Formally, if the two points are (x0, y0) and (x1, y1), then the slope
* is (y1 - y0) / (x1 - x0). For completeness, the slope is defined to be
* +0.0 if the line segment connecting the two points is horizontal;
* Double.POSITIVE_INFINITY if the line segment is vertical;
* and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal.
*
* @param that the other point
* @return the slope between this point and the specified point
*/
public double slopeTo(Point that) {
if (this.x == that.x && this.y == that.y){
return Double.NEGATIVE_INFINITY;
}
if (this.x == that.x){
return Double.POSITIVE_INFINITY;
}
if (this.y == that.y){
return +0.0;
}
return (double)(that.y - this.y) / (that.x - this.x);
}
/**
* Compares two points by y-coordinate, breaking ties by x-coordinate.
* Formally, the invoking point (x0, y0) is less than the argument point
* (x1, y1) if and only if either y0 < y1 or if y0 = y1 and x0 < x1.
*
* @param that the other point
* @return the value <tt>0</tt> if this point is equal to the argument
* point (x0 = x1 and y0 = y1);
* a negative integer if this point is less than the argument
* point; and a positive integer if this point is greater than the
* argument point
*/
public int compareTo(Point that) {
if (this.y == that.y){
return this.x - that.x;
}else{
return this.y - that.y;
}
/*if (this.y - that.y > 0){
return 1;
}
else if(this.y - that.y < 0){
return -1;
}
else{
if (this.x - that.x > 0)
return 1;
else if (this.x - that.x < 0)
return -1;
else
return 0;
}*/
}
/**
* Compares two points by the slope they make with this point.
* The slope is defined as in the slopeTo() method.
*
* @return the Comparator that defines this ordering on points
*/
public Comparator<Point> slopeOrder() {
return new SlopeOrder();
}
private class SlopeOrder implements Comparator<Point>{
public int compare(Point p1, Point p2){
double s1 = slopeTo(p1);
double s2 = slopeTo(p2);
//return (int) (s1-s2);
if (s1 < s2)
return -1;
else if (s1 > s2)
return 1;
else
return 0;
}
}
/**
* Returns a string representation of this point.
* This method is provide for debugging;
* your program should not rely on the format of the string representation.
*
* @return a string representation of this point
*/
public String toString() {
/* DO NOT MODIFY */
return "(" + x + ", " + y + ")";
}
/**
* Unit tests the Point data type.
*/
public static void main(String[] args) {
/* YOUR CODE HERE */
}
}

View File

@ -0,0 +1,46 @@
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.In;
public class TestClient{
public static void main(String[] args) {
// read the n points from a file
In in = new In(args[0]);
int n = in.readInt();
/*int n = 8;
int[] x_all = new int[]{10000, 0, 3000, 7000, 20000, 3000, 14000, 6000};
int[] y_all = new int[]{0, 10000, 7000, 3000, 21000, 4000, 15000, 7000};*/
/*int n = 6;
int[] x_all = new int[]{19000, 18000, 32000, 21000, 1234, 14000};
int[] y_all = new int[]{10000, 10000, 10000, 10000, 5678, 10000};*/
Point[] points = new Point[n];
for (int i = 0; i < n; i++) {
int x = in.readInt();
int y = in.readInt();
points[i] = new Point(x, y);
//points[i] = new Point(x_all[i], y_all[i]);
}
// draw the points
StdDraw.enableDoubleBuffering();
//32768
StdDraw.setXscale(0, 32768);
StdDraw.setYscale(0, 32768);
for (Point p : points) {
p.draw();
}
StdDraw.show();
// print and draw the line segments
FastCollinearPoints collinear = new FastCollinearPoints(points);
for (LineSegment segment : collinear.segments()) {
StdOut.println(segment);
segment.draw();
}
StdDraw.show();
}
}

View File

@ -0,0 +1,233 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Board {
private int[][] board;
private final int board_dim;
private int hamming_dist;
private int manhattan_dist;
private int empty_pos;
// create a board from an n-by-n array of tiles,
// where tiles[row][col] = tile at (row, col)
public Board(int[][] tiles){
if (tiles == null){
throw new IllegalArgumentException("inital board cannot be null.");
}
board = new int[tiles.length][];
hamming_dist = 0;
manhattan_dist = 0;
// Make a copy of the board, and calculate the distance
int val = 0;
int row, col;
for(int i = 0; i < tiles.length; i++){
board[i] = tiles[i].clone();
for(int j = 0; j < tiles.length; j++){
val = tiles[i][j];
if(val > 0){
row = (val-1)/tiles.length;
col = (val-1)%tiles.length;
if (i != row || j != col){
hamming_dist++;
manhattan_dist += Math.abs(row-i)+Math.abs(col-j);
}
}
else{
empty_pos = i*tiles.length + j;
}
}
}
board_dim = tiles.length;
}
// string representation of this board
public String toString(){
String tile_str = "";
tile_str += board_dim + "\n";
for(int i = 0; i < board_dim; i++){
for(int j = 0; j < board_dim; j++){
tile_str += board[i][j] + " ";
}
tile_str += "\n";
}
return tile_str;
}
// board dimension n
public int dimension(){
return board_dim;
}
// number of tiles out of place
public int hamming(){
return hamming_dist;
}
// sum of Manhattan distances between tiles and goal
public int manhattan(){
return manhattan_dist;
}
// is this board the goal board?
public boolean isGoal(){
int last_val = board_dim * board_dim;
for(int i=0; i<board_dim;i++){
for(int j=0; j<board_dim;j++){
if (board[i][j] != (1+j+i*board_dim)%last_val)
return false;
}
}
return true;
}
// does this board equal y?
public boolean equals(Object y){
if (y != null && y.getClass().isInstance(this) ){
if (y.toString().equals(toString()))
return true;
}
return false;
}
// all neighboring boards
public Iterable<Board> neighbors(){
return new neighbourIterable();
}
// a board that is obtained by exchanging any pair of tiles
public Board twin(){
int[][] new_board = new int[board_dim][board_dim];
for(int i = 0; i < board_dim; i++)
new_board[i] = board[i].clone();
if (board_dim>1){
int empty_row = empty_pos/board_dim;
int empty_col= empty_pos%board_dim;
int target_row = 0;
if (empty_row == 0 && empty_col<2)
target_row = 1;
new_board[target_row][0] += new_board[target_row][1];
new_board[target_row][1] = new_board[target_row][0] - new_board[target_row][1];
new_board[target_row][0] -= new_board[target_row][1];
}
return new Board(new_board);
}
private class neighbourIterable implements Iterable<Board>{
private Board[] neighbours;
private int n_neighbours;
public neighbourIterable(){
int empty_row = empty_pos/board_dim;
int empty_col= empty_pos%board_dim;
neighbours = new Board[4];
n_neighbours=0;
int[][] new_board = new int[board_dim][board_dim];
for(int i = 0; i < board_dim; i++)
new_board[i] = board[i].clone();
if (empty_row > 0){
new_board[empty_row][empty_col] = new_board[empty_row-1][empty_col];
new_board[empty_row-1][empty_col] = 0;
neighbours[n_neighbours++] = new Board(new_board);
new_board[empty_row-1][empty_col] = new_board[empty_row][empty_col];
new_board[empty_row][empty_col] = 0;
}
if (empty_row < board_dim-1){
new_board[empty_row][empty_col] = new_board[empty_row+1][empty_col];
new_board[empty_row+1][empty_col] = 0;
neighbours[n_neighbours++] = new Board(new_board);
new_board[empty_row+1][empty_col] = new_board[empty_row][empty_col];
new_board[empty_row][empty_col] = 0;
}
if (empty_col > 0){
new_board[empty_row][empty_col] = new_board[empty_row][empty_col-1];
new_board[empty_row][empty_col-1] = 0;
neighbours[n_neighbours++] = new Board(new_board);
new_board[empty_row][empty_col-1] = new_board[empty_row][empty_col];
new_board[empty_row][empty_col] = 0;
}
if (empty_col < board_dim-1){
new_board[empty_row][empty_col] = new_board[empty_row][empty_col+1];
new_board[empty_row][empty_col+1] = 0;
neighbours[n_neighbours++] = new Board(new_board);
new_board[empty_row][empty_col+1] = new_board[empty_row][empty_col];
new_board[empty_row][empty_col] = 0;
}
}
public Iterator<Board> iterator(){
return new neighbourIterator();
}
private class neighbourIterator implements Iterator<Board>{
int current = 0;
public boolean hasNext(){
return current < n_neighbours;
}
public void remove(){
throw new UnsupportedOperationException("Remove operation is not supported.");
}
public Board next(){
if (!hasNext()){
throw new NoSuchElementException("No next item.");
}
return neighbours[current++];
}
}
}
// unit testing (not graded)
public static void main(String[] args){
int size = 3;
int[][] tiles = new int[size][size];
for (int i=0;i<size;i++){
for(int j=0;j<size;j++){
tiles[i][j] = i*size+j+1;
}
}
tiles[size-1][size-1] = tiles[1][1];
tiles[1][1] = 0;
Board board = new Board(tiles);
Board board2 = new Board(tiles);
System.out.println(board.toString());
System.out.println(board.manhattan());
System.out.println(board.hamming());
System.out.println(board.isGoal());
System.out.println(board.equals(null));
System.out.println(board.equals(tiles));
System.out.println(board.equals(board2));
board2 = board.twin();
System.out.println(board2.toString());
System.out.println(board.equals(board2));
System.out.println(board.toString());
Iterable<Board> board_neighbours = board.neighbors();
Iterator<Board> iter = board_neighbours.iterator();
while(iter.hasNext()){
System.out.println(iter.next().toString());
}
}
}

View File

@ -0,0 +1,287 @@
//import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
public class Solver {
// This class is a linked list for storing checked boards
/*private class CheckedBoard{
public Board board;
public CheckedBoard next;
}*/
// This class is used to store the state
private class BoardState implements Comparable<BoardState>{
public Board current_board;
public BoardState prev_state;
public int moves;
private int priority;
public BoardState(Board board, BoardState prev_state, int moves){
current_board = board;
this.prev_state = prev_state;
this.moves = moves;
//priority = board.hamming() + moves;
priority = board.manhattan() + moves;
}
public int compareTo(BoardState that) {
return this.priority - that.priority;
}
}
private boolean solvable;
private BoardState final_state;
// find a solution to the initial board (using the A* algorithm)
public Solver(Board initial){
if (initial == null){
throw new IllegalArgumentException("inital board cannot be null.");
}
// Initialise the initial BoardState
BoardState initialBoardState = new BoardState(initial, null, 0);
// Initialise minPQ and put the initial BoardState
MinPQ<BoardState> priority_queue = new MinPQ<BoardState>();
priority_queue.insert(initialBoardState);
// Get also the twin version and initial its own minPQ
MinPQ<BoardState> priority_queue_twin = new MinPQ<BoardState>();
priority_queue_twin.insert(new BoardState(initial.twin(), null, 0));
//Initiate checkedboard linked list
/*CheckedBoard head = new CheckedBoard();
head.board = initialBoardState.current_board;
head.next = null;
//Do the same for the twin
CheckedBoard head_twin = new CheckedBoard();
head_twin.board = initial.twin();
head_twin.next = null;*/
BoardState state = initialBoardState;
Iterable<Board> state_neighbours;
Iterator<Board> iter;
//CheckedBoard new_board;
// While both PQ is not empty
while(!(priority_queue.isEmpty() && priority_queue_twin.isEmpty())){
// delmin
if (!priority_queue.isEmpty()){
state = priority_queue.delMin();
//check isGoal
if (!state.current_board.isGoal()){
//If not, get the neighbours.
state_neighbours = state.current_board.neighbors();
iter = state_neighbours.iterator();
//For each neighbour
Board next_board;
while(iter.hasNext()){
next_board = iter.next();
boolean checked = false;
BoardState current_state = state;
for(int i=0;i<1;i++){
current_state = current_state.prev_state;
if (current_state == null){
break;
}
else{
if(next_board.equals(current_state.current_board)){
checked = true;
break;
}
}
}
/*CheckedBoard current_checkedBoard = head;
// Check if the board has been checked before
while(current_checkedBoard != null){
if(next_board.equals(current_checkedBoard.board)){
checked = true;
break;
}
current_checkedBoard = current_checkedBoard.next;
}*/
//If not create a new BoardState
if (!checked){
BoardState new_state = new BoardState(next_board, state, state.moves+1);
//Push to PQ
priority_queue.insert(new_state);
// Put current board in checkedBoard list
/*new_board = new CheckedBoard();
new_board.board = next_board;
new_board.next = head;
head = new_board;*/
}
}
}else{
//Otherwise, break
break;
}
}
if (!priority_queue_twin.isEmpty()){
// REPEAT FOR THE TWIN
state = priority_queue_twin.delMin();
//check isGoal
if (!state.current_board.isGoal()){
//If not, get the neighbours.
state_neighbours = state.current_board.neighbors();
iter = state_neighbours.iterator();
//For each neighbour, check if in checkedState
Board next_board;
while(iter.hasNext()){
next_board = iter.next();
boolean checked = false;
BoardState current_state = state;
for(int i=0;i<1;i++){
current_state = current_state.prev_state;
if (current_state == null){
break;
}
else{
if(next_board.equals(current_state.current_board)){
checked = true;
break;
}
}
}
/*CheckedBoard current_checkedBoard = head_twin;
while(current_checkedBoard != null){
if(next_board.equals(current_checkedBoard.board)){
checked = true;
break;
}
current_checkedBoard = current_checkedBoard.next;
}*/
//If not create a new BoardState, set prev to this
if (!checked){
BoardState new_state = new BoardState(next_board, state, state.moves+1);
//Push to PQ
priority_queue_twin.insert(new_state);
// Put current board in checkedBoard
/*new_board = new CheckedBoard();
new_board.board = state.current_board;
new_board.next = head_twin;
head_twin = new_board;*/
}
}
}else{
//Otherwise, break
break;
}
}
}
// The puzzle must be solvable for either one of them
// Check if the starting board is original or twin
// If original, solvable; otherwise no.
BoardState current_state = state;
while(current_state.prev_state != null){
current_state = current_state.prev_state;
}
solvable = current_state.current_board.equals(initialBoardState.current_board);
if (solvable){
final_state = state;
}else{
final_state = initialBoardState;
}
}
// is the initial board solvable? (see below)
public boolean isSolvable(){
return solvable;
}
// min number of moves to solve initial board
public int moves(){
if (solvable)
return final_state.moves;
return -1;
}
// sequence of boards in a shortest solution
public Iterable<Board> solution(){
if (solvable)
return new solutionIterable();
return null;
}
private class solutionIterable implements Iterable<Board>{
Board[] solution_boards;
public solutionIterable(){
//generate the iterable by tracing back from
//the final BoardState using prev_board recursively
//Number fo recursions determined by moves;
solution_boards = new Board[final_state.moves+1];
BoardState current_state = final_state;
for(int i=final_state.moves;i>=0;i--){
solution_boards[i] = current_state.current_board;
current_state = current_state.prev_state;
}
}
public Iterator<Board> iterator(){
return new solutionIterator();
}
private class solutionIterator implements Iterator<Board>{
int current = 0;
public boolean hasNext(){
return current < solution_boards.length;
}
public void remove(){
throw new UnsupportedOperationException("Remove operation is not supported.");
}
public Board next(){
if (!hasNext()){
throw new NoSuchElementException("No next item.");
}
return solution_boards[current++];
}
}
}
// test client (see below)
public static void main(String[] args){// create initial board from file
In in = new In(args[0]);
int n = in.readInt();
int[][] tiles = new int[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
tiles[i][j] = in.readInt();
Board initial = new Board(tiles);
StdOut.println(initial.toString());
// solve the puzzle
Solver solver = new Solver(initial);
// print solution to standard output
if (!solver.isSolvable())
StdOut.println("No solution possible");
else {
StdOut.println("Minimum number of moves = " + solver.moves());
for (Board board : solver.solution())
StdOut.println(board);
}
}
}

View File

@ -0,0 +1,473 @@
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.In;
import java.util.Iterator;
public class KdTree {
private final int VERTICAL = 0;
private final int HORIZONTAL = 1;
private class pointNode{
public Point2D p;
public pointNode left = null;
public pointNode right = null;
public int line_type;
}
private pointNode root;
private int n_points;
// construct an empty set of points
public KdTree(){
root = null;
n_points = 0;
}
// is the set empty?
public boolean isEmpty(){
return (root == null);
}
// number of points in the set
public int size(){
return n_points;
}
// add the point to the set (if it is not already in the set)
public void insert(Point2D p){
if (p == null){
throw new IllegalArgumentException("Point is null.");
}
if (isEmpty()){
root = new pointNode();
root.p = p;
root.line_type = VERTICAL;
n_points++;
}else{
add(p, root);
}
}
private void add(Point2D p, pointNode node){
// Check if current node is p
if (node.p.equals(p)){
return;
}
if (node.line_type == VERTICAL){
//compare x to decide traversal direction
if (p.x() < node.p.x()){
// check if the direction is null
if (node.left == null){
// insert node if null
node.left = new pointNode();
node.left.p = p;
node.left.line_type = HORIZONTAL;
n_points++;
}else{
// recurse add if not
add(p, node.left);
}
}else{
if (node.right == null){
node.right = new pointNode();
node.right.p = p;
node.right.line_type = HORIZONTAL;
n_points++;
}else{
// recurse add if not
add(p, node.right);
}
}
}else{
if (p.y() < node.p.y()){
// check if the direction is null
if (node.left == null){
// insert node if null
node.left = new pointNode();
node.left.p = p;
node.left.line_type = VERTICAL;
n_points++;
}else{
// recurse add if not
add(p, node.left);
}
}else{
if (node.right == null){
node.right = new pointNode();
node.right.p = p;
node.right.line_type = VERTICAL;
n_points++;
}else{
// recurse add if not
add(p, node.right);
}
}
}
}
// does the set contain point p?
public boolean contains(Point2D p){
if (p == null){
throw new IllegalArgumentException("Point is null.");
}
if (isEmpty()){
return false;
}else{
return search(p, root);
}
}
private boolean search(Point2D p, pointNode node){
// Check if current node is p
if (node.p.equals(p)){
return true;
}
if (node.line_type == VERTICAL){
//compare x to decide traversal direction
if (p.x() < node.p.x()){
if (node.left != null)
return search(p, node.left);
return false;
}else{
if (node.right != null)
return search(p, node.right);
return false;
}
}else{
if (p.y() < node.p.y()){
if (node.left != null)
return search(p, node.left);
return false;
}else{
if (node.right != null)
return search(p, node.right);
return false;
}
}
}
// draw all points to standard draw
public void draw(){
if (!isEmpty()){
inorder_draw(root, 0, 0, 1, 1);
}
//StdDraw.show();
}
private void inorder_draw(pointNode node, double xmin, double ymin, double xmax, double ymax){
if (node.left != null){
if(node.line_type == VERTICAL){
inorder_draw(node.left, xmin, ymin, node.p.x(), ymax);
}else{
inorder_draw(node.left, xmin, ymin, xmax, node.p.y());
}
}
//Insert draw routine
StdDraw.setPenRadius(0.005);
if(node.line_type == VERTICAL){
StdDraw.setPenColor(StdDraw.RED);
StdDraw.line(node.p.x(), ymin, node.p.x(), ymax);
}else{
StdDraw.setPenColor(StdDraw.BLUE);
StdDraw.line(xmin, node.p.y(), xmax, node.p.y());
}
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
StdDraw.point(node.p.x(), node.p.y());
if (node.right != null){
if(node.line_type == VERTICAL){
inorder_draw(node.right, node.p.x(), ymin, xmax, ymax);
}else{
inorder_draw(node.right, xmin, node.p.y(), xmax, ymax);
}
}
}
// all points that are inside the rectangle (or on the boundary)
public Iterable<Point2D> range(RectHV rect){
if (rect == null){
throw new IllegalArgumentException("Rect is null.");
}
if (!isEmpty()){
Point2D[] p_array = new Point2D[n_points];
int[] n = new int[1];
n[0] = 0;
range_search(root, rect, p_array, n, 0, 0, 1, 1);
return new point_iterable(p_array, n[0]);
}
return null;
}
private void range_search(pointNode node, RectHV rect, Point2D[] p_array, int[] n, double xmin, double ymin, double xmax, double ymax){
// Check for point
if (rect.contains(node.p)){
p_array[n[0]++] = node.p;
}
if (node.left != null){
// Check for rect intersection
// Then traverse
if(node.line_type == VERTICAL){
if (rect.intersects(new RectHV(xmin, ymin, node.p.x(), ymax)))
range_search(node.left, rect, p_array, n, xmin, ymin, node.p.x(), ymax);
}else{
if (rect.intersects(new RectHV(xmin, ymin, xmax, node.p.y())))
range_search(node.left, rect, p_array, n, xmin, ymin, xmax, node.p.y());
}
}
if (node.right != null){
if(node.line_type == VERTICAL){
if (rect.intersects(new RectHV(node.p.x(), ymin, xmax, ymax)))
range_search(node.right, rect, p_array, n, node.p.x(), ymin, xmax, ymax);
}else{
if (rect.intersects(new RectHV(xmin, node.p.y(), xmax, ymax)))
range_search(node.right, rect, p_array, n, xmin, node.p.y(), xmax, ymax);
}
}
}
// a nearest neighbor in the set to point p; null if the set is empty
public Point2D nearest(Point2D p){
if (p == null){
throw new IllegalArgumentException("Point is null.");
}
if (isEmpty()){
return null;
}
Point2D[] nearest_p = new Point2D[1];
nearest_p[0] = root.p;
double[] shortest_dist = new double[1];
shortest_dist[0] = p.distanceSquaredTo(root.p);
//System.out.println(root.p.toString());
// Update the nearest point so far if there is none or one is found
double straight_dist = Math.pow(p.x() - root.p.x(), 2);
boolean to_left = p.x() < root.p.x();
//can probably generalise this
if (to_left){
if (root.left != null)
nearest_neighbour(root.left , p, nearest_p, shortest_dist, 0, 0, root.p.x(), 1);
if (root.right != null && straight_dist < shortest_dist[0]){
// Need a separate check for other side
// Get the two intersecting points which the short distance circle
// makes with the root vertical line
double x_dist = Math.abs(root.p.x() - p.x());
double y_dist = Math.sqrt(shortest_dist[0] - x_dist * x_dist);
double y_min = Math.max(p.y() - y_dist, 0);
double y_max = Math.min(p.y() + y_dist, 1);
nearest_neighbour(root.right, p, nearest_p, shortest_dist, root.p.x(), 0, 1, 1);
}
}else{
if (root.right != null)
nearest_neighbour(root.right , p, nearest_p, shortest_dist, root.p.x(), 0, 1, 1);
if (root.left != null && straight_dist < shortest_dist[0]){
// Need a separate check for other side
// Get the two intersecting points which the short distance circle
// makes with the root vertical line
nearest_neighbour(root.left, p, nearest_p, shortest_dist, 0, 0, root.p.x(), 1);
}
}
return nearest_p[0];
}
private void nearest_neighbour(pointNode node, Point2D p, Point2D[] nearest_p, double[] shortest_dist, double xmin, double ymin, double xmax, double ymax){
//System.out.println(node.p.toString());
// This is a check for the points opposite of the query point
double dist = p.distanceSquaredTo(node.p);
// Update the nearest point so far if there is none or one is found
if (dist < shortest_dist[0]){
nearest_p[0] = node.p;
shortest_dist[0] = dist;
}
RectHV rect;
double point_dist;
// This is the rigorous version of the checking
// Using on the distance of the query point to the rectangle enclosed by the spillter
// Comparing to the shortest distance to see if there is an overlap
if (node.line_type == HORIZONTAL){
// Have a check which direction to go
boolean to_left = p.y() < node.p.y();
if (to_left){
rect = new RectHV(xmin, ymin , xmax, node.p.y());
point_dist = rect.distanceSquaredTo(p);
if (node.left != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.left, p, nearest_p, shortest_dist, xmin, ymin , xmax, node.p.y());
}
rect = new RectHV(xmin, node.p.y() , xmax, ymax);
point_dist = rect.distanceSquaredTo(p);
if (node.right != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.right, p, nearest_p, shortest_dist, xmin, node.p.y() , xmax, ymax);
}
}else{
rect = new RectHV(xmin, node.p.y() , xmax, ymax);
point_dist = rect.distanceSquaredTo(p);
if (node.right != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.right, p, nearest_p, shortest_dist, xmin, node.p.y() , xmax, ymax);
}
rect = new RectHV(xmin, ymin , xmax, node.p.y());
point_dist = rect.distanceSquaredTo(p);
if (node.left != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.left, p, nearest_p, shortest_dist, xmin, ymin , xmax, node.p.y());
}
}
}else{
// For vertical line
boolean to_left = p.x() < node.p.x();
if (to_left){
rect = new RectHV(xmin, ymin , node.p.x(), ymax);
point_dist = rect.distanceSquaredTo(p);
if (node.left != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.left, p, nearest_p, shortest_dist, xmin, ymin , node.p.x(), ymax);
}
rect = new RectHV(node.p.x(), ymin , xmax, ymax);
point_dist = rect.distanceSquaredTo(p);
if (node.right != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.right, p, nearest_p, shortest_dist, node.p.x(), ymin , xmax, ymax);
}
}else{
rect = new RectHV(node.p.x(), ymin , xmax, ymax);
point_dist = rect.distanceSquaredTo(p);
if (node.right != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.right, p, nearest_p, shortest_dist, node.p.x(), ymin , xmax, ymax);
}
rect = new RectHV(xmin, ymin , node.p.x(), ymax);
point_dist = rect.distanceSquaredTo(p);
if (node.left != null && point_dist < shortest_dist[0]){
nearest_neighbour(node.left, p, nearest_p, shortest_dist, xmin, ymin , node.p.x(), ymax);
}
}
}
}
/*private void nearest_neighbour(pointNode node, Point2D p, Point2D[] nearest_p, double[] shortest_dist){
System.out.println(node.p.toString());
double dist = p.distanceSquaredTo(node.p);
// Update the nearest point so far if one is found
if (dist < shortest_dist[0]){
nearest_p[0] = node.p;
shortest_dist[0] = dist;
}
// This is the simplified version of the checking
// Using on the straight line dist from the splitter
// Make use of the fact that the query point is on the same side
// Check which direction to go on the splitter
double straight_dist;
boolean to_left;
if(node.line_type == VERTICAL){
straight_dist = Math.pow(p.x() - node.p.x(), 2);
to_left = p.x() < node.p.x();
}else{
straight_dist = Math.pow(p.y() - node.p.y(), 2);
to_left = p.y() < node.p.y();
}
// Go on the side with the point
// After checking the side of the splitter with the point,
// Only go to the other side if the straight distance is less than the shortest distance
// This is because the circle by the shortest distance overlaps both side of the spiltter if so
if (to_left){
if (node.left != null){
nearest_neighbour(node.left, p, nearest_p, shortest_dist);
}
if (node.right != null && straight_dist < shortest_dist[0]){
nearest_neighbour(node.right, p, nearest_p, shortest_dist);
}
}else{
if (node.right != null){
nearest_neighbour(node.right, p, nearest_p, shortest_dist);
}
if (node.left != null && straight_dist < shortest_dist[0]){
nearest_neighbour(node.left, p, nearest_p, shortest_dist);
}
}
}
*/
private class point_iterable implements Iterable<Point2D> {
Point2D[] points_array;
public point_iterable(Point2D[] points, int n){
points_array = new Point2D[n];
for(int i=0;i<n;i++){
points_array[i] = points[i];
}
}
public Iterator<Point2D> iterator(){
return new point_iterator();
}
private class point_iterator implements Iterator<Point2D>{
private int current = 0;
public boolean hasNext(){
return current < points_array.length;
}
public Point2D next(){
return points_array[current++];
}
}
}
// unit testing of the methods (optional)
public static void main(String[] args) {
KdTree kdtree = new KdTree();
In in = new In("test_traversal.txt");
while (!in.isEmpty()) {
double x = in.readDouble();
double y = in.readDouble();
Point2D p = new Point2D(x, y);
System.out.println("inserting");
kdtree.insert(p);
System.out.println(kdtree.size());
}
System.out.println(kdtree.contains(new Point2D(0.48, 0.04)));
System.out.println(kdtree.contains(new Point2D(-2, 0)));
System.out.println("Nearest: " + kdtree.nearest(new Point2D(0.46875, 0.125)));
}
}

View File

@ -0,0 +1,54 @@
/******************************************************************************
* Compilation: javac KdTreeVisualizer.java
* Execution: java KdTreeVisualizer
* Dependencies: KdTree.java
*
* Add the points that the user clicks in the standard draw window
* to a kd-tree and draw the resulting kd-tree.
*
******************************************************************************/
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.In;
public class KdTreeVisualizer {
public static void main(String[] args) {
RectHV rect = new RectHV(0.0, 0.0, 1.0, 1.0);
StdDraw.enableDoubleBuffering();
KdTree kdtree = new KdTree();
/*String filename = args[0];
In in = new In(filename);
while (!in.isEmpty()) {
double x = in.readDouble();
double y = in.readDouble();
Point2D p = new Point2D(x, y);
kdtree.insert(p);
}*/
while (true) {
if (StdDraw.isMousePressed()) {
double x = StdDraw.mouseX();
double y = StdDraw.mouseY();
StdOut.printf("%8.6f %8.6f\n", x, y);
Point2D p = new Point2D(x, y);
if (rect.contains(p)) {
//StdOut.printf("%8.6f %8.6f\n", x, y);
kdtree.insert(p);
StdDraw.clear();
kdtree.draw();
StdDraw.show();
}
}
StdDraw.pause(20);
}
/*StdDraw.setPenColor(StdDraw.GREEN);
StdDraw.setPenRadius(0.01);
StdDraw.point(0.46875, 0.125);
kdtree.draw();
StdDraw.show();*/
}
}

View File

@ -0,0 +1,64 @@
/******************************************************************************
* Compilation: javac NearestNeighborVisualizer.java
* Execution: java NearestNeighborVisualizer input.txt
* Dependencies: PointSET.java KdTree.java
*
* Read points from a file (specified as a command-line argument) and
* draw to standard draw. Highlight the closest point to the mouse.
*
* The nearest neighbor according to the brute-force algorithm is drawn
* in red; the nearest neighbor using the kd-tree algorithm is drawn in blue.
*
******************************************************************************/
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.StdDraw;
public class NearestNeighborVisualizer {
public static void main(String[] args) {
// initialize the two data structures with point from file
String filename = args[0];
In in = new In(filename);
PointSET brute = new PointSET();
KdTree kdtree = new KdTree();
while (!in.isEmpty()) {
double x = in.readDouble();
double y = in.readDouble();
Point2D p = new Point2D(x, y);
kdtree.insert(p);
brute.insert(p);
}
// process nearest neighbor queries
StdDraw.enableDoubleBuffering();
while (true) {
// the location (x, y) of the mouse
double x = StdDraw.mouseX();
double y = StdDraw.mouseY();
Point2D query = new Point2D(x, y);
// draw all of the points
StdDraw.clear();
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
brute.draw();
// draw in red the nearest neighbor (using brute-force algorithm)
StdDraw.setPenRadius(0.03);
StdDraw.setPenColor(StdDraw.RED);
brute.nearest(query).draw();
StdDraw.setPenRadius(0.02);
// draw in blue the nearest neighbor (using kd-tree algorithm)
StdDraw.setPenColor(StdDraw.BLUE);
kdtree.nearest(query).draw();
StdDraw.show();
StdDraw.pause(40);
}
}
}

View File

@ -0,0 +1,125 @@
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.SET;
import java.util.Iterator;
public class PointSET {
private SET<Point2D> set_points;
// construct an empty set of points
public PointSET(){
set_points = new SET<Point2D>();
}
// is the set empty?
public boolean isEmpty(){
return set_points.isEmpty();
}
// number of points in the set
public int size(){
return set_points.size();
}
// add the point to the set (if it is not already in the set)
public void insert(Point2D p){
if (p == null){
throw new IllegalArgumentException("Point is null.");
}
if (!set_points.contains(p))
set_points.add(p);
}
// does the set contain point p?
public boolean contains(Point2D p){
return set_points.contains(p);
}
// draw all points to standard draw
public void draw(){
Iterator<Point2D> iter = set_points.iterator();
while (iter.hasNext()){
iter.next().draw();
}
//StdDraw.show();
}
// all points that are inside the rectangle (or on the boundary)
public Iterable<Point2D> range(RectHV rect){
if (rect == null){
throw new IllegalArgumentException("Rect is null.");
}
Iterator<Point2D> iter = set_points.iterator();
Point2D p;
Point2D[] p_array = new Point2D[set_points.size()];
int n = 0;
while (iter.hasNext()){
p = iter.next();
if (rect.contains(p)){
p_array[n++] = p;
}
}
return new point_iterable(p_array, n);
}
// a nearest neighbor in the set to point p; null if the set is empty
public Point2D nearest(Point2D p){
if (p == null){
throw new IllegalArgumentException("Point is null.");
}
if (set_points.isEmpty()){
return null;
}
Point2D current_p;
double current_dist = 0;
Point2D nearest_p = null;
double shortest_dist = -1;
Iterator<Point2D> iter = set_points.iterator();
while (iter.hasNext()){
current_p = iter.next();
current_dist = p.distanceSquaredTo(current_p);
if (shortest_dist < 0 || current_dist < shortest_dist){
nearest_p = current_p;
shortest_dist = p.distanceSquaredTo(current_p);
}
}
return nearest_p;
}
private class point_iterable implements Iterable<Point2D> {
Point2D[] points_array;
public point_iterable(Point2D[] points, int n){
points_array = new Point2D[n];
for(int i=0;i<n;i++){
points_array[i] = points[i];
}
}
public Iterator<Point2D> iterator(){
return new point_iterator();
}
private class point_iterator implements Iterator<Point2D>{
private int current = 0;
public boolean hasNext(){
return current < points_array.length;
}
public Point2D next(){
return points_array[current++];
}
}
}
// unit testing of the methods (optional)
public static void main(String[] args) {
}
}

View File

@ -0,0 +1,99 @@
/******************************************************************************
* Compilation: javac RangeSearchVisualizer.java
* Execution: java RangeSearchVisualizer input.txt
* Dependencies: PointSET.java KdTree.java
*
* Read points from a file (specified as a command-line argument) and
* draw to standard draw. Also draw all of the points in the rectangle
* the user selects by dragging the mouse.
*
* The range search results using the brute-force algorithm are drawn
* in red; the results using the kd-tree algorithms are drawn in blue.
*
******************************************************************************/
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.StdDraw;
public class RangeSearchVisualizer {
public static void main(String[] args) {
// initialize the data structures from file
String filename = args[0];
In in = new In(filename);
PointSET brute = new PointSET();
KdTree kdtree = new KdTree();
while (!in.isEmpty()) {
double x = in.readDouble();
double y = in.readDouble();
Point2D p = new Point2D(x, y);
kdtree.insert(p);
brute.insert(p);
}
double x0 = 0.0, y0 = 0.0; // initial endpoint of rectangle
double x1 = 0.0, y1 = 0.0; // current location of mouse
boolean isDragging = false; // is the user dragging a rectangle
// draw the points
StdDraw.clear();
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
brute.draw();
StdDraw.show();
// process range search queries
StdDraw.enableDoubleBuffering();
while (true) {
// user starts to drag a rectangle
if (StdDraw.isMousePressed() && !isDragging) {
x0 = x1 = StdDraw.mouseX();
y0 = y1 = StdDraw.mouseY();
isDragging = true;
}
// user is dragging a rectangle
else if (StdDraw.isMousePressed() && isDragging) {
x1 = StdDraw.mouseX();
y1 = StdDraw.mouseY();
}
// user stops dragging rectangle
else if (!StdDraw.isMousePressed() && isDragging) {
isDragging = false;
}
// draw the points
StdDraw.clear();
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
brute.draw();
// draw the rectangle
RectHV rect = new RectHV(Math.min(x0, x1), Math.min(y0, y1),
Math.max(x0, x1), Math.max(y0, y1));
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius();
rect.draw();
// draw the range search results for brute-force data structure in red
StdDraw.setPenRadius(0.03);
StdDraw.setPenColor(StdDraw.RED);
for (Point2D p : brute.range(rect))
p.draw();
// draw the range search results for kd-tree in blue
StdDraw.setPenRadius(0.02);
StdDraw.setPenColor(StdDraw.BLUE);
for (Point2D p : kdtree.range(rect))
p.draw();
StdDraw.show();
StdDraw.pause(20);
}
}
}