Programming Assignment 1: Percolation
阿新 • • 發佈:2019-01-02
Percolation
實現Percolation模型。
用蒙特卡羅模擬估計滲濾閾值的值。
關於backwash問題:有了一個虛擬底層位置,如果網格已經滲透了。這時判斷其中一個位置(與底部相連,並且底部是開啟的,與虛擬底層位置相連)是否滿(即與虛擬頂層位置是相連的),那麼不管這個位置是不是真的滿,結果總會是滿的。因為網格已經滲透了,那麼虛擬頂層位置與虛擬底層位置總是相連的,而這個位置與虛擬頂層位置是相連的,這時候再判斷它是不是滿(與虛擬頂層位置相連),結果當然總是為真。
這裡提供了兩種方法解決backwash,即迴流問題
Percolation with top virtual site
即帶有虛擬位置的網格。
同時需要建立兩個WeightedQuickUnionUF 物件,一個同時有虛擬頂層位置和虛擬底層位置,這樣判斷是否滲透很容易。另一個只有虛擬頂層位置,這就避免了迴流問題,用來判斷是否滿。
由於建立了兩個WeightedQuickUnionUF 物件,所以 記憶體使用沒有完全過關,得到了97分。
Percolation.java
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
/**
* The {@code Percolation} class provides methods for calculating the Percolation.
* <p>
* Creates two WeightedQuickUnionUF objects to solve the backwash problem.
*
* @author zhangyu
* @date 2017.2.27
*/
public class Percolation
{
private int size; // size of created grid
private int[] status; // record the status of each site
private WeightedQuickUnionUF grid;
private WeightedQuickUnionUF gridNoVBottom;
/**
* Initializes two WeightedQuickUnionUF object. One has two
* virtual sites, and the other one has only one top site.
* Set state of each site blocked.
*
* @param n size of created grid
* @throws IllegalArgumentException if n < 1
*/
public Percolation(int n)
{
if (n < 1) throw new IllegalArgumentException("Grid size out of range");
size = n;
status = new int[n * n];
for (int i = 0; i < n * n; i++) status[i] = 0;
grid = new WeightedQuickUnionUF(n*n + 2);
gridNoVBottom = new WeightedQuickUnionUF(n*n + 1);
}
/**
* open site (row, col) if it is not open already.
*
* @param row abscissa of the grid
* @param col ordinate of the grid
*/
public void open(int row, int col)
{
int idx = xyTo1D(row, col);
validate(row, col);
status[idx] = 1;
if (1 == row) // connect to the virtual site
{
grid.union(idx, size * size);
gridNoVBottom.union(idx, size * size);
}
if (size == row) grid.union(idx, size*size + 1);
int[] xDiff = {-1, 1, 0, 0};
int[] yDiff = {0, 0, -1, 1};
for (int i = 0; i < 4; i++)
{
int adjX = row + xDiff[i];
int adjY = col + yDiff[i];
if (adjX > 0 && adjX <= size)
{
if (adjY > 0 && adjY <= size)
{
int adjPosIdx = xyTo1D(adjX, adjY);
if (1 == status[adjPosIdx])
{
grid.union(idx, adjPosIdx);
gridNoVBottom.union(idx, adjPosIdx);
}
}
}
}
}
/**
* Determine whether the site (row, col) is open.
*
* @param row abscissa of the grid
* @param col ordinate of the grid
* @return true if the site (row, col) is open;
* false otherwise
*/
public boolean isOpen(int row, int col)
{
validate(row, col);
return status[xyTo1D(row, col)] == 1;
}
/**
* Determine whether the site (row, col) is full.
*
* @param row abscissa of the grid
* @param col ordinate of the grid
* @return true if the site (row, col) is full;
* false otherwise
*/
public boolean isFull(int row, int col)
{
validate(row, col);
return isOpen(row, col) && gridNoVBottom.connected(xyTo1D(row, col), size * size);
}
/**
* Returns the number of open sites.
*
* @return the number of open sites
*/
public int numberOfOpenSites()
{
int sum = 0;
for (int i = 0; i < status.length; i++) sum += status[i];
return sum;
}
/**
* Determine whether the grid percolates.
*
* @return true if the grid percolates.
* false otherwise
*/
public boolean percolates()
{
return grid.connected(size * size, size*size + 1);
}
//map 2D coordinates to 1D coordinates
private int xyTo1D(int row, int col)
{
return (row - 1)*size + col - 1;
}
// validate that (row, col) is valid
private void validate(int row, int col)
{
if (row < 1 || row > size || col < 1 || col > size)
throw new IndexOutOfBoundsException("index: (" + row + ", " + col + ") are out of bounds");
}
/**
* Unit tests the {@code Percolation} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args)
{
int n = StdIn.readInt();
Percolation client = new Percolation(n);
while (!StdIn.isEmpty())
{
int row = StdIn.readInt();
int col = StdIn.readInt();
client.open(row, col);
StdOut.println(client.isOpen(row, col));
StdOut.println(client.isFull(row, col));
StdOut.println(client.percolates());
}
}
}
ASSESSMENT SUMMARY
Compilation: PASSED
API: PASSED
Findbugs: PASSED
Checkstyle: FAILED (2 warnings)
Correctness: 26/26 tests passed
Memory: 5/8 tests passed
Timing: 9/9 tests passed
Aggregate score: 96.25%
[Compilation: 5%, API: 5%, Findbugs: 0%, Checkstyle: 0%, Correctness: 60%, Memory: 10%, Timing: 20%]
Percolation without virtual sites
不帶虛擬位置的網格。
只建立一個WeightedQuickUnionUF 物件,沒有虛擬位置。使用很多標籤來判斷開啟,阻塞,與頂部相連,與底部相連和滲透這幾種狀態。當一個位置與頂部相連,就是滿狀態,當它既是與頂部相連,又是與底部相連,這個網格就是滲透的。在開啟一個位置時,就同時更新他們的狀態,如果相鄰的位置是開啟的,那麼除了合併區域使它們相連,還要互相將狀態進行或操作,即每個位置得到相鄰位置的狀態,為了使每個部分的位置的狀態都能更新,就必須更新根位置的狀態。
由於使用的是位元組型別和或操作。所以記憶體使用的不多(少了一個WeightedQuickUnionUF 物件),得到了一個bonus:),100分。
Percolation.java
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
/**
* The {@code Percolation} class provides methods for calculating the Percolation.
* <p>
* Creates only one WeightedQuickUnionUF object to solve the backwash problem.
*
* @author zhangyu
* @date 2017.2.27
*/
public class Percolation
{
private static final byte BLOCKED = Byte.valueOf("0"); // 00000000
private static final byte OPEN = Byte.valueOf("1"); // 00000001
private static final byte TOPCONNECTED = Byte.valueOf("2"); // 00000010
private static final byte BOTTOMCONNECTED = Byte.valueOf("4"); // 00000100
private static final byte PERCOLATED = Byte.valueOf("7"); // 00000111
private int size; // size of created grid
private byte[] state; // record the state of each site
private int openSites; // number of open sites
private boolean percolate = false;
private WeightedQuickUnionUF grid;
/**
* Initializes one WeightedQuickUnionUF object, without
* any virtual site. Set state of each site blocked.
*
* @param n size of created grid
* @throws IllegalArgumentException if n < 1
*/
public Percolation(int n) // create n-by-n grid, with all sites blocked
{
if (n < 1) throw new IllegalArgumentException("Grid size out of range");
size = n;
state = new byte[n * n];
for (int i = 0; i < n * n; i++) state[i] = BLOCKED;
grid = new WeightedQuickUnionUF(n * n);
}
/**
* open site (row, col) if it is not open already.
*
* @param row abscissa of the grid
* @param col ordinate of the grid
*/
public void open(int row, int col)
{
validate(row, col);
int idx = xyTo1D(row, col);
int[] xDiff = {-1, 1, 0, 0};
int[] yDiff = {0, 0, -1, 1};
// if the site has been opened, then return
if (0 != (state[idx] & OPEN)) return;
state[idx] = (byte)(state[idx] | OPEN);
if (1 == row) state[idx] = (byte)(state[idx] | TOPCONNECTED);
if (size == row) state[idx] = (byte)(state[idx] | BOTTOMCONNECTED);
for (int i = 0; i < 4; i++)
{
int adjX = row + xDiff[i];
int adjY = col + yDiff[i];
if (adjX > 0 && adjX <= size)
{
if (adjY > 0 && adjY <= size)
{
int adjSiteIdx = xyTo1D(adjX, adjY); // index of the adjacent site
int rootASIdx = grid.find(adjSiteIdx);
if (OPEN == (state[adjSiteIdx] & OPEN)) // if the adjacent site is open
{
state[idx] = (byte)(state[idx] | state[rootASIdx]);
grid.union(idx, adjSiteIdx); // union the two components
}
}
}
}
int rootIdx = grid.find(idx); // must get root index after union operation
state[rootIdx] = (byte)(state[rootIdx] | state[idx]);
if (PERCOLATED == (byte)(state[rootIdx] & PERCOLATED))
percolate = true;
openSites++;
}
/**
* Determine whether the site (row, col) is open.
*
* @param row abscissa of the grid
* @param col ordinate of the grid
* @return true if the site (row, col) is open;
* false otherwise
*/
public boolean isOpen(int row, int col)
{
validate(row, col);
return OPEN == (state[xyTo1D(row, col)] & OPEN);
}
/**
* Determine whether the site (row, col) is full.
*
* @param row abscissa of the grid
* @param col ordinate of the grid
* @return true if the site (row, col) is full;
* false otherwise
*/
public boolean isFull(int row, int col)
{
validate(row, col);
int rootIdx = grid.find(xyTo1D(row, col)); // root index of given site (row, col)
return isOpen(row, col) && TOPCONNECTED == (state[rootIdx] & TOPCONNECTED);
}
/**
* Returns the number of open sites.
*
* @return the number of open sites
*/
public int numberOfOpenSites()
{
return openSites;
}
/**
* Determine whether the grid percolates.
*
* @return true if the grid percolates.
* false otherwise
*/
public boolean percolates()
{
return percolate;
}
//map 2D coordinates to 1D coordinates
private int xyTo1D(int row, int col)
{
return (row - 1)*size + col - 1;
}
// validate that (row, col) is valid
private void validate(int row, int col)
{
if (row < 1 || row > size || col < 1 || col > size)
throw new IndexOutOfBoundsException("index: (" + row + ", " + col + ") are out of bounds");
}
/**
* Unit tests the {@code Percolation} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args)
{
int n = StdIn.readInt();
Percolation client = new Percolation(n);
while (!StdIn.isEmpty())
{
int row = StdIn.readInt();
int col = StdIn.readInt();
client.open(row, col);
StdOut.println(client.isOpen(row, col));
StdOut.println(client.isFull(row, col));
StdOut.println(client.percolates());
}
}
}
ASSESSMENT SUMMARY
Compilation: PASSED
API: PASSED
Findbugs: PASSED
Checkstyle: FAILED (8 warnings)
Correctness: 26/26 tests passed
Memory: 9/8 tests passed
Timing: 9/9 tests passed
Aggregate score: 101.25%
[Compilation: 5%, API: 5%, Findbugs: 0%, Checkstyle: 0%, Correctness: 60%, Memory: 10%, Timing: 20%]
PercolationStats.java
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
/**
* The {@code PercolationStats} class performs independent experiment, using
* the Percolation data structure. Then compute the mean and standard
* deviation of results.
* <p>
* It also provides method to compute confidence intervals for them.
*
* @author zhangyu
* @date 2017.2.27
*/
public class PercolationStats
{
private int trials;
private double[] threshold;
/**
* perform trials independent experiments on an n-by-n grid
*
* @param n size of created grid
* @param trials times of experiments
* @throws IllegalArgumentException unless
* both grid size and value of trials out of range
*/
public PercolationStats(int n, int trials)
{
if (n < 1)
throw new IllegalArgumentException("Grid size out of range");
if (trials < 1)
throw new IllegalArgumentException("value of trials out of range");
this.trials = trials;
threshold = new double[trials];
for (int i = 0; i < trials; i++)
{
Percolation expModel = new Percolation(n);
while (!expModel.percolates())
{
int row = StdRandom.uniform(n) + 1;
int col = StdRandom.uniform(n) + 1;
expModel.open(row, col);
}
threshold[i] = (double)expModel.numberOfOpenSites() / (double)(n*n);
}
}
/**
* Returns the sample mean of percolation threshold.
*
* @return the sample mean of percolation threshold
*/
public double mean()
{
return StdStats.mean(threshold);
}
/**
* Returns the sample standard deviation of percolation threshold.
*
* @return the sample standard deviation of percolation threshold
*/
public double stddev()
{
return StdStats.stddev(threshold);
}
/**
* Returns the low endpoint of 95% confidence interval.
*
* @return the low endpoint of 95% confidence interval.
*/
public double confidenceLo()
{
return mean() - 1.96*stddev() / Math.sqrt(trials);
}
/**
* Returns the high endpoint of 95% confidence interval.
*
* @return the high endpoint of 95% confidence interval.
*/
public double confidenceHi()
{
return mean() + 1.96*stddev() / Math.sqrt(trials);
}
/**
* Unit tests the {@code PercolationStats} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args)
{
int n, trials;
n = StdIn.readInt();
trials = StdIn.readInt();
PercolationStats client = new PercolationStats(n, trials);
StdOut.println("mean = " + client.mean());
StdOut.println("stddev = " + client.stddev());
StdOut.println("95% confidence interval = " + "[" + client.confidenceLo() + ", "
+ client.confidenceHi() + "]");
}
}