动态连通性算法分析总结
1·动态连通性
性质:
1·自反性——p和p是相连的;
2·对称性——如果p和q相连,那么q和p也相连;
3·传递性——如果p和q相连,q和r相连,那么p和r也相连。
2·union-find算法实现
Public class UF
{
Private int[] id;
Private int count;
Public UF(int N)
{
Count=N;
Id=new int [N];
For(int i=0;i<N;i++)
{
Id[i]=I;
}
}
Public int count()
{
Return count;
}
Public Boolean connected(int p,int q)
{
Return find(p) == find(q);
}
Public int find ()
{}
Public void union (int p,int q)
{}
//测试用例
Public static void main(String[] args)
{
Int N=StdIn.readInt();
UF uf=new UF(N);
While(!StdIn.isEmpty())
{
Int p= StdIn.readInt();
Int q= StdIn.readInt();
If(uf.connected(p,q)) continue;
Uf.union(p,q);
StdOut.println(p+”“+q);
}
StdOut.println(uf.count()+ “components”);
}
}
3·三种算法的比较
(1) quick-find算法
a.代码
private int find(int p)
{
return id[p];
}
Private void union(int p, int q)
{
int pid = id[p];
int qid = id[q];
if(pid == qid)
return;
for(int i=0;i<id.length;i++)
if(id[i] == pid)id[i]=qid;
count--;
}
b.性能分析
上述算法的性能主要取决于对于数组id[]的访问。我们每调用一次find()函数,就会对数组id[]进行一次访问;而我们每调用一次union()函数就会对数组产生至少(1+1+N+1)次访问,最多产生(1+1+2*N-1)次访问。所以,当我们需要完成对N个节点的连接时,对于数组的访问次数就会介于(N+3)*N和(2N+1)*N之间。这也就意味着,时间会随着规模呈平方级增长。
(2) quick-union算法
a.代码
private int find(int p)
{
while (p != id[p])
p = id[p];
return p;
}
private void union(int p, int q)
{
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;
id[rootP] = rootQ;
count--;
}
b.性能分析
首先进行一些定义说明:树的大小——树中节点的数目;树中一个节点的深度——它到根节点的路径上的连接数;树的高度——所有节点的最大深度。
上述算法的性能主要取决于对于数组id[]的访问。我们每调用一次find()函数,就会对数组id[]进行访问的次数为1加上给定的点的深度的2倍;而我们每调用一次union()函数就会调用2次find操作。所以,当我们需要完成对N个节点的连接时,对于数组的访问次数为2*2*(1+2+……+N)。这也同样意味着,时间会随着规模呈平方级增长。
(3) 加权quick-union算法
a.代码
public int find(int p)
{
while (p != id[p])
p = id[p];
return p;
}
public void union(int p, int q)
{
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;
// make smaller root point to larger one
if (sz[rootP] <sz[rootQ])
{ id[rootP] = rootQ;
sz[rootQ] += sz[rootP]; }
else
{ id[rootQ] = rootP; sz[rootP] +=sz[rootQ]; }
count--;
}
b.性能分析