改进
经过几轮提交,改进一下几点:
- 重复代码提取为private方法
- 整个scope中反复使用的变量定义为private final
- 使用的常量定义为常量private static final
经过论坛中提示,修改的几点:
- 实例化两个WeightedQuickUnionUF:A用来记录上下结点和方块节点的连接关系、B用来记录上节点和方块节点的连接关系
- 因为在判断isFull时,是判断某节点是否和方块中第一排节点相连。如果用A,由于底部一排节点和下虚节点相连,如下图,当判断下图p点isFull时,可以通过下虚节点找到第一排。所以需要用B。
/Percolation///
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
public class Percolation {
private boolean[][] open;
private int count;
private final WeightedQuickUnionUF wquuf1; // t & b
private final WeightedQuickUnionUF wquuf2; // only top
private final int len;
public Percolation(int n) {
if (n <= 0) throw new IllegalArgumentException();
open = new boolean[n + 1][n + 1];
wquuf1 = new WeightedQuickUnionUF(n * n + 2); // n*n+2 -> top & bottom virtual point
wquuf2 = new WeightedQuickUnionUF(n * n + 1); // n*n+1 -> top virtual point
len = n; // n
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= n; j++) {
open[i][j] = false;
}
}
// 初始绑定虚节点
for (int i = 0; i < n; i++) {
union(i, n * n);
wquuf1.union((n - 1) * n + i, n * n + 1);
}
}
private void validate(int row, int col) {
if (row < 1 || row > len || col < 1 || col > len) {
throw new IllegalArgumentException();
}
}
private void union(int p, int q) {
wquuf1.union(p, q);
wquuf2.union(p, q);
}
private int dConvertor(int row, int col) {
return (row - 1) * len + (col - 1);
}
public void open(int row, int col) {
this.validate(row, col);
if (open[row][col]) {
return;
}
open[row][col] = true;
count++;
int tp = dConvertor(row, col); // this point in wquuf
int cp; // connected point in wquuf
if ((row - 1) >= 1 && open[row - 1][col]) {
cp = dConvertor(row - 1, col);
union(tp, cp);
}
if ((row + 1) <= len && open[row + 1][col]) {
cp = dConvertor(row + 1, col);
union(tp, cp);
}
if ((col - 1) >= 1 && open[row][col - 1]) {
cp = dConvertor(row, col - 1);
union(tp, cp);
}
if ((col + 1) <= len && open[row][col + 1]) {
cp = dConvertor(row, col + 1);
union(tp, cp);
}
}
public boolean isOpen(int row, int col) {
this.validate(row, col);
return open[row][col];
}
public boolean isFull(int row, int col) {
this.validate(row, col);
if (!open[row][col]) return false; //如果不是open肯定不是full
return wquuf2.find(len * len) == wquuf2.find(dConvertor(row, col));
}
public int numberOfOpenSites() {
return count;
}
public boolean percolates() {
return wquuf1.find(len * len) == wquuf1.find(len * len + 1);
}
}
/PercolationStats///
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
public class PercolationStats {
private static final double CONFIDENCE_95 = 1.96;
private final double[] xt;
// perform independent trials on an n-by-n grid
public PercolationStats(int n, int trials) {
if (n <= 0 || trials <= 0) throw new IllegalArgumentException();
int x, y;
xt = new double[trials];
for (int i = 0; i < trials; i++) {
Percolation percolation = new Percolation(n);
while (!percolation.percolates()) {
x = StdRandom.uniform(1, n + 1);
y = StdRandom.uniform(1, n + 1);
percolation.open(x, y);
}
xt[i] = (double) percolation.numberOfOpenSites() / n / n;
}
}
// sample mean of percolation threshold
public double mean() {
// StdOut.println(Arrays.toString(xt));
return StdStats.mean(xt);
}
// sample standard deviation of percolation threshold
public double stddev() {
if (xt.length == 1) return Double.NaN;
return StdStats.stddev(xt);
}
// low endpoint of 95% confidence interval
public double confidenceLo() {
return this.mean() - CONFIDENCE_95 / Math.sqrt(xt.length);
}
// high endpoint of 95% confidence interval
public double confidenceHi() {
return this.mean() + CONFIDENCE_95 / Math.sqrt(xt.length);
}
// test client (see below)
public static void main(String[] args) {
PercolationStats percolationStats = new PercolationStats(Integer.parseInt(args[0]),
Integer.parseInt(args[1]));
StdOut.printf("mean = %.6f\n", percolationStats.mean());
StdOut.printf("stddev = %.17f\n", percolationStats.stddev());
StdOut.printf("95%% confidence interval = [%.15f, %.15f]\n",
percolationStats.confidenceLo(), percolationStats.confidenceHi());
}
}