1. 程式人生 > >Programming Assignment 1: Percolation

Programming Assignment 1: Percolation

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() + "]");
    }
}