动态联通性问题描述:
有N个元素,开始时我们让每一个元素肚子构成一个集合。然后按一定的顺序将属于同一组中的元素合并,构成新的集合。其间要反复查询某个元素在哪个集合中。如下所示:
(1)Quick-Find
声明一个长度为N的数组id,数组中元素的值代表它所属组的编号。将数组中的元素初始化为每个元素的索引值,这样就表示开始时每个元素各自构成一个独立的集合。每次union(i,j)的时候就将所有组编号等于id[i]的元素的组编号变为id[j]。每次查询元素i的组编号时,返回id[i]即可。
时间复杂度分析:union操作的时间复杂度为O(n),find操作的时间复杂度为O(1)
(2) Quick-Union
同样是声明一个长度为N的int型数组id。但与Quick-Find方法不同的是,Quick-Union让每一个集合中的元素构成一棵树。
每一个元素对应的id存的是自己在树上的父节点。在执行union(i,j)操作时,将i元素所在树的根指向j所在元素的根。在查询元素i的id时,返回元素i所在集合的树的根节点index即可。
时间复杂度分析:union操作的时间复杂度为O(n),find的时间复杂度为O(n).
(3)Weighted Quick-Union
为了防止构建树的过程中出现tall trees,我们记录每个集合的大小。每次union的时候将小集合对应树的根链接到大集合所对应树的根上。
时间复杂度分析:union操作的时间复杂度为lg(n),find操作的时间复杂度为lg(n).
(4) Path compression Quick-Union
我们将p指向root路径上的每个节点都展开指向root。
性能总结
Programming Assignment : Percolation
import edu.princeton.cs.algs4.WeightedQuickUnionUF;//直接调用WeightedQuickUnion算法API
import edu.princeton.cs.algs4.StdOut;
public class Percolation {
private boolean status[];
private int size;
private WeightedQuickUnionUF UF;
private WeightedQuickUnionUF UFTop;
private int getPosition(int row,int col){//将方格(row,col)转换成一个数字
return (row-1)*size+col;
}
private void checkBounds(int row,int col){//判断方格是否过界
if(row<1||col<1||row>size||col>size)
throw new IndexOutOfBoundsException("Index out of bounds");
}
private boolean isOpen(int pos){//判断方格是否打开
return status[pos]==true;
}
private void union(int aPos,int bPos,WeightedQuickUnionUF aUF){
if(!aUF.connected(aPos,bPos))//若两点未连接
aUF.union(aPos,bPos);//则直接union
}
/**
* Instantiates a new Percolation.
*
* @param n the n
*/
public Percolation(int n) {//初始化n*n个方格
if(n<1)
throw new IllegalArgumentException("Illegal argument");
size=n;
status = new boolean[n * n + 2];//加上虚拟方格
for(int i=1;i<n*n+1;i++)
status[i]=false;//n*n个方格关闭
status[0]=status[n*n+1]=true;//虚拟方格打开
UF=new WeightedQuickUnionUF(n*n+2);
UFTop=new WeightedQuickUnionUF(n*n+1);
}
/**
* Open.
*
* @param row the row
* @param col the col
*/
public void open(int row,int col) {
checkBounds(row, col);
if(isOpen(row,col))
return;
int nowPos=getPosition(row,col);
int prevRowPos=getPosition(row-1,col),nextRowPos=getPosition(row+1,col),
prevColPos=getPosition(row,col-1),nextColPos=getPosition(row,col+1);
status[nowPos]=true;//将该方格打开
if(row==1){//该方格位于第一行,连接顶层的虚拟方格
union(0,nowPos,UF);
union(0,nowPos,UFTop);
}
else if(isOpen(prevRowPos)){//将该方格与位于其下边的方格连接
union(nowPos,prevRowPos,UF);
union(nowPos,prevRowPos,UFTop);
}
if(row==size){//该方格位于最后一行,连接底层的虚拟方格
union(size*size+1,nowPos,UF);
}
else if(isOpen(nextRowPos))//将该方格与位于其上边的方格连接
{
union(nowPos,nextRowPos,UF);
union(nowPos, nextRowPos, UFTop);
}
if(col!=1&&isOpen(prevColPos)){//如果该方格未位于最左侧,则将其与左侧打开的方格连接
union(nowPos, prevColPos, UF);
union(nowPos, prevColPos, UFTop);
}
if (col!= size && isOpen(nextColPos)) {//如果该方格未位于最右侧,则将其与右侧打开的方格连接
union(nowPos,nextColPos,UF);
union(nowPos,nextColPos,UFTop);
}
}
/**
* Is full boolean.
*
* @param row the row
* @param col the col
* @return the boolean
*/
public boolean isFull(int row,int col) {//判断该方格与顶层虚拟方格是否联通
checkBounds(row,col);
return UFTop.connected(0, getPosition(row, col));
}
/**
* Is open boolean.
*
* @param row the row
* @param col the col
* @return the boolean
*/
public boolean isOpen(int row,int col) {
checkBounds(row,col);
return isOpen(getPosition(row,col));
}
/**
* Number of open sites int.
*
* @return the int
*/
public int numberOfOpenSites() {
int count=0;
for(int i=1;i<size*size+1;i++) {
count+=(status[i]==true?1:0);
}
return count;
}
/**
* Percolates boolean.
*
* @return the boolean
*/
public boolean percolates() { //判断底层虚拟方格与顶层虚拟方格是否联通
return UF.connected(0,size*size+1);
}
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
StdOut.println("This is a simple check for pecolation!");
}
}
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdStats;
import edu.princeton.cs.algs4.StdIn;
/**
* Created by Administrator on 2017/3/31.
*/
//采用蒙特卡洛算法
public class PercolationStats {
private double[] attemps;
/**
* Instantiates a new Percolation stats.
*
* @param N the n
* @param trails the trails
*/
public PercolationStats(int N, int trails) {//N为矩阵长度,trails为试验次数
if (N <= 0 || trails <= 0)
throw new IllegalArgumentException("Illegal Argument!");
attemps = new double[trails];
for (int i = 0; i < trails; i++) {
Percolation checkPerco = new Percolation(N);//初始化方格,全设置为关闭状态
int step = 0;
while (!checkPerco.percolates()) {//表示顶层节点与底层节点未联通,直到联通,统计开放状态的方格个数
int row = StdRandom.uniform(N) + 1;
int column = StdRandom.uniform(N) + 1;
if (!checkPerco.isOpen(row, column)) {
checkPerco.open(row, column);//随机使某个方格开放
step++;
}
}
attemps[i] = (double) step / (N * N);
}
}
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
int N = StdIn.readInt();
int T = StdIn.readInt();
PercolationStats ps = new PercolationStats(N, T);
StdOut.printf("%-25s= %.7f\n", "mean", ps.mean());
StdOut.printf("%-25s= %.17f\n", "stddev", ps.stddev());
StdOut.printf("%-25s= [%.15f, %.15f]\n", "95% confidence interval",
ps.confidenceLo(), ps.confidenceHi());
}
/**
* Mean double.
*
* @return the double
*/
public double mean() {
return StdStats.mean(attemps);
}
/**
* Stddev double.
*
* @return the double
*/
public double stddev() {
return StdStats.stddev(attemps);
}
/**
* Confidence lo double.
*
* @return the double
*/
public double confidenceLo() {
return mean() - ((1.96 * stddev())) / Math.sqrt(attemps.length);
}
/**
* Confidence hi double.
*
* @return the double
*/
public double confidenceHi() {
return mean() + ((1.96 * stddev())) / Math.sqrt(attemps.length);
}
}