First commit
commit
7f5a224a40
|
@ -0,0 +1,5 @@
|
|||
Week*/*
|
||||
!.gitignore
|
||||
!Week*/src/
|
||||
*.zip
|
||||
*.jar
|
|
@ -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("");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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("");
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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("");
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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();*/
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue