Week1 - Union-Find
本周作业为实现Percolation Model(渗透模型),并在此基础上完成Monte Carlo simulation(蒙特卡洛模拟).
题目可见http://coursera.cs.princeton.edu/algs4/assignments/percolation.html
实现代码如下
Percolation.java
import edu.princeton.cs.algs4.In; import edu.princeton.cs.algs4.WeightedQuickUnionUF; public class Percolation { private final int gridLength; //方形系统的边长 private boolean[] grid; //初始化数组来表示网格的状态,true为开放,false为关闭 private final WeightedQuickUnionUF wqu; //设定加权quick-union算法,该算法中包含virtualTop与virtualBottom private final WeightedQuickUnionUF wqu2; //设定加权quick-union算法,该算法中仅包含virtualTop来防止底部回流问题 /* 为什么要防止底部回流问题?因为在wqu函数中,我们认为最下面一行的节点,已经默认与我们的底部虚拟节点相连 这就会导致我们实际打开的节点数(Open sites)与渗透成功时实际充满的节点数(Full sites)个数不一致 因此,若要计算Full sites,我们只需将wqu中的节点作为变量通过wqu2来观察其是否与顶部虚拟节点相连即可 */ private final int virtualTop; //设置顶部虚拟节点 private final int virtualBottom; //设置底部虚拟节点 private int openedNum = 0; //统计开启的节点个数 // create n-by-n grid, with all sites blocked public Percolation(int n) { if (n <= 0) { throw new IllegalArgumentException("length must be positive"); } this.gridLength = n; grid = new boolean[gridLength * gridLength + 2]; //网格包括所有的点和设置的两个虚拟节点,boolean默认为false wqu = new WeightedQuickUnionUF(gridLength * gridLength + 2); wqu2 = new WeightedQuickUnionUF(gridLength * gridLength + 1); virtualTop = 0; //赋值顶部虚拟节点为0 virtualBottom = gridLength * gridLength + 1; //赋值底部虚拟节点为网格数+1 } // open site (row, col) if it is not open already public void open(int row, int col) { validateIndecies(row, col); int site = xyTo1D(row, col); grid[site] = true; if (row == 1) { //第一行的所有节点默认与顶部虚拟节点相连 wqu.union(site, virtualTop); wqu2.union(site, virtualTop); } if (row == gridLength) { //最后一行的所有节点默认与底部虚拟节点相连 wqu.union(site, virtualBottom); } // to open the way if the sites next to the self are open int neighbour; // up if (row > 1) { neighbour = xyTo1D(row -1, col); if (grid[neighbour]) { wqu.union(site, neighbour); wqu2.union(site, neighbour); } } // down if (row < gridLength) { neighbour = xyTo1D(row + 1, col); if (grid[neighbour]) { wqu.union(site, neighbour); wqu2.union(site, neighbour); } } // left if (col > 1) { neighbour = xyTo1D(row, col - 1); if (grid[neighbour]) { wqu.union(site, neighbour); wqu2.union(site, neighbour); } } // right if (col < gridLength) { neighbour = xyTo1D(row, col + 1); if (grid[neighbour]) { wqu.union(site, neighbour); wqu2.union(site, neighbour); } } openedNum++; } //验证行数与列数是否越界 private void validateIndecies(int row, int col) { if (row < 0 || row > gridLength) { throw new IndexOutOfBoundsException("row index out of bounds"); } if (col < 0 || col > gridLength) { throw new IndexOutOfBoundsException("col index out of bounds"); } } //将平面二维网格转化为一维格点值 private int xyTo1D(int row, int col) { validateIndecies(row, col); return (row - 1) * gridLength + col; } // is site (row, col) open? public boolean isOpen(int row, int col) { validateIndecies(row, col); return grid[xyTo1D(row, col)]; } // is site (row, col) full? // A full site is an open site that can be connected to an open site in the top row via a chain of neighboring (left, right, up, down) open sites. public boolean isFull(int row, int col) { validateIndecies(row, col); return wqu2.connected(virtualTop, xyTo1D(row, col)); } // number of open sites public int numberOfOpenSites() { return openedNum; } // does the system percolate? public boolean percolates() { return wqu.connected(virtualTop, virtualBottom); } // test client (optional) public static void main(String[] args) { In in = new In("input7.txt"); int n = in.readInt(); Percolation percolation = new Percolation(n); while (!in.isEmpty()) { int row = in.readInt(); int col = in.readInt(); percolation.open(row, col); } System.out.println("percolation is" + percolation.percolates()); } }
PercolationStats.java
import edu.princeton.cs.algs4.StdOut; import edu.princeton.cs.algs4.StdRandom; import edu.princeton.cs.algs4.StdStats; public class PercolationStats { private final int gridLength; // 系统边长 private double[] trailsResult;// 进行percolation试验每一次所需要的open sites的个数 private double mean; // 平均值 // 平均数是一组样本x1,x2,x3,...,xn的和除以样本的数量n private double stddev; // 标准偏差 // 标准偏差(Standard Deviation)是描述个数据偏离平均数的距离的平均数 private double confidenceLow; // 最低置信度 private double confidenceHigh; // 最高置信度 // 置信区间是对这个样本的某个总体参数的区间估计,它所表示的是这个总体参数的真实值有一定概率落在罗在于该测量结果有关的某对应区间 // 举例来说,如果在一次大选中某人的支持率为55%,而置信水平0.95上的置信区间是(50%,60%),那么他的真实支持率落在50%和60%之区间的机率为95%,因此他的真实支持率不足50%的可能性小于2.5%(假设分布是对称的) // perform trials independent experiments on an n-by-n grid // 在n*n的网格中进行trials次percolation试验 public PercolationStats(int n, int trials) { if (n <= 0) { throw new IllegalArgumentException("gridLength must be positive"); } if (trials <= 0) { throw new IllegalArgumentException("trials must be positive"); } gridLength = n; if (gridLength == 1) { mean = 1; stddev = Double.NaN; confidenceLow = Double.NaN; confidenceHigh = Double.NaN; // NaN(Not a Number,非数)是计算机科学中数值数据类型的一个值,表示未定义或不可表示的值。常在浮点数运算中使用。 // 在本题中,由于n=1时网格仅有一个节点,因此在计算标准偏差时可能会出现0/0的情况 // 为了避免非法的数值的产生,利用NaN与任何浮点数(包括自身)的比较结果都为假,即 (NaN ≠ x) = false的特性来返回一个正常的值 // 更详细的说明可见 https://www.cnblogs.com/big-xuyue/p/4106130.html } else { trailsResult = new double[trials]; for (int i = 0; i < trials; i++) {// 进行trails次运算,获得结果集并存储在doubble[]的trailsResult里 trailsResult[i] = oneTrial(gridLength); } mean = StdStats.mean(trailsResult); stddev = StdStats.stddev(trailsResult); double diff = (1.96 * stddev) / Math.sqrt(trials);// 该计算式由题目给出 confidenceLow = mean - diff; confidenceHigh = mean + diff; } } private double oneTrial(int length) { Percolation percolation = new Percolation(length); while (!percolation.percolates()) { int row = StdRandom.uniform(length) + 1;// 由于Random表示[0,target)的取值区间,因此+1以排除0并包含target int col = StdRandom.uniform(length) + 1; if (!percolation.isOpen(row, col)) { percolation.open(row, col); } } return (double) percolation.numberOfOpenSites() / (length * length); } // sample mean of percolation threshold public double mean() { return mean; } // sample standard deviation of percolation threshold public double stddev() { return stddev; } // low endpoint of 95% confidence interval public double confidenceLo() { return confidenceLow; } // high endpoint of 95% confidence interval public double confidenceHi() { return confidenceHigh; } // test client (described below) public static void main(String[] args) { int length = 2; int trials = 2; PercolationStats percolations = new PercolationStats(length, trials); StdOut.println("mean = " + percolations.mean()); StdOut.println("stddev = " + percolations.stddev()); StdOut.println("95% confidence interval = " + percolations.confidenceLo() + ", " + percolations.confidenceHi()); } }