1.3:Union-Find算法-----quick-union算法的改进(加权的quick-union算法)

对于一般情况而言,使用quick-union算法就已经足够满足需求。但是仍然存在着一种情况使得quick-union算法得到的最快的情况。

quick-union的最坏情况:

当我们要对两个节点进行union操作时,等价于对两个节点所在的分量进行union操作(对于分量,用“树”这个词来表示更为妥当。因为一个节点总是指向它的“父节点”)。此时union(p, q)即将前者(p)的根节点指向后者(q)的根节点。若此时p所在的树的大小(即p所在分量节点的个数) 远大于 q所在树的大小。则经过若干次这样的操作后,树将会变得及其不平衡。这带来的直接后果是树的高度将接近所有分量的节点数目。这样一来,查找花费的代价将及其昂贵。如下图:

1.3:Union-Find算法-----quick-union算法的改进(加权的quick-union算法)_第1张图片

对于最坏情况的解决方案:

为了防止避免这种最坏情况的发生,一种解决方法是在连接两个节点(即连接两颗树时)进行判断,那棵树的节点多,然后将比较小的树连接到较大的一棵树上面。

1.3:Union-Find算法-----quick-union算法的改进(加权的quick-union算法)_第2张图片

可以看出,在连接前判断树的大小并将小树连接到大树的方法明显使得树更加平衡。这种方法叫做加权的quick-union算法。

代码如下:

public class WeightedQuickUnionUF {
	private int[] id;	//节点数组
	private int[] sz;	//用来保存各个根节点对应的分量大小
	private int count;	//连通分量的数量
	
	public WeightedQuickUnionUF(int N) {
		count = N;
		
		id = new int[N];
		for(int i = 0; i < N; i++)
			id[i] = i;
		
		sz = new int[N];
		for(int i = 0; i < N; i++)
			sz[i] = 1;
	}
	
	public int count() {
		return count;
	}
	
	public boolean connected(int p, int q) {
		return find(p) == find(q);
	}
	
	public int find(int p) {		
		while(p != id[p]) p = id[p];
		return p;
	}
	
	public void union(int p, int q) {
		int i = find(p);
		int j = find(q);
		if(i == j)	return;
		
		if(sz[i] < sz[j])	{id[i] = j; sz[j] += sz[i];}  
		else			{id[j] = i; sz[i] += sz[j];}
		
		count--;
	}	
}



你可能感兴趣的:(1.3:Union-Find算法-----quick-union算法的改进(加权的quick-union算法))