Algorithms,Part 1(第一周)

代码和笔记整理

笔记简单整理

1.导入jar包的操作
2.设计类先抽象功能和需要用到的变量
3.先设计测试类的接口
4.一定要讨论数据结构和算法的应用场景
5.算法的时间复杂度需要自己跑跑试试,学会测试一切自己想测试的东西,不要迷信权威

并查集(Union-Find)

接口抽象

package unionFind;

import edu.princeton.cs.algs4.*;

public class UF {
	
	//初始化
    public UF(int n) {
		// TODO 自动生成的构造函数存根
	}
	boolean connected(int p, int q) {
		return false;
	}
	//合并
	void union(int p ,int q) {}
	
	public static void main(String[] args) {
		 //TODO 自动生成的方法存根
		//输入规模
		int N = StdIn.readInt();
		//初始化
		UF uf = new UF(N);
		//初始化一些Union
		while (!StdIn.isEmpty()) {
			int p = StdIn.readInt();
			int q = StdIn.readInt();
			if(!uf.connected(p,q)) {
				uf.union(p,q);
				StdOut.println(p+" "+q);
			}
		}
		//接下来可以判断任意两个值是否“相连”
	}

}

QuickFind实现

package unionFind;

import edu.princeton.cs.algs4.*;


public class QuickFindUF {
	//id标识着他们所在的集合
	private int[] id;
	//初始化
	public QuickFindUF(int N){
		id = new int[N];
		for(int i = 0; i < N; i++) {
			id[i] = i;
		}
	}
	public boolean connected(int p, int q) {
		return (id[p] == id[q]);
	}
	public void union(int p ,int q) {
		int pid = id[p];
		int qid = id[q];
		for(int i = 0;i < id.length; i++) {
			//union(q,p)指的是把所有跟p的id一样的点的id全部改为q的id
			if(id[i] == pid) {
				id[i] = qid;
			}
		}
	}
}

时间复杂度:建立O(n),判断是否相连的connected操作为O(1),合并union操作为O(n)。
这里假设我们在用Quick-Find方法解决动态连通性问题时最终只得到了一个连通分量,那么我们在实际应用中至少要调用N-1次Union,所以显然它对于最终只能得到少数连通分量的一般应用是O(n2)级别的。

QuickUnion实现(加权、路径压缩)

package unionFind;

import edu.princeton.cs.algs4.*;

public class QuickUnionUF {
	//每个节点的父节点
	private int[] id;
	private int[] sz;
	public QuickUnionUF(int N){
		sz = new int[N];
		id = new int[N];
		for(int i = 0; i < id.length; i++) {
			id[i] = i;
		}
	}
	private int root(int i) {
		while(id[i] != i) {
			//路径压缩!!简单的两次寻找可以让树的结构更好,深度大大减少的话,是非常划算的做法。
			id[i] = id[id[i]];
			i = id[i];
		}
		return i;
	}
	public boolean connected(int p, int q) {
		return (root(p) == root(q));
	}
	public void union(int p ,int q) {
		int proot = root(p);
		int qroot = root(q);
		if(proot == qroot) {
			return;
		}
		//加权!,永远把小树加在大树上
		if(sz[proot] < sz[qroot]) {
			id[proot] = qroot;
			sz[qroot] += sz[proot];
		}else {
			id[qroot] = proot;
			sz[proot] += sz[qroot];
		}		
	}
}

基础的Quick-Union只改良了QF算法的union操作,其union和connected操作的复杂度跟树高有关,但是最差情况下还是N级别,还不够,上文给出的是加权的QU算法(加权部分已注释),它一定有不超过log2n的树高,其union和connected操作都具有对数级别log2n的性能。路径压缩后效果更佳好。
遵循前面说的测试才是真理的想法,拿我的破电脑跑了一下1百万行的largeUF.txt(官网给的有 http://algs4.cs.princeton.edu/15uf/largeUF.txt ),还是挺慢的,吃饭期间挂着最后跑了15分钟跑出来了。不过如果用QF的方法,估计我自己这个破笔记本有生之间系列了。

猜你喜欢

转载自blog.csdn.net/u013453787/article/details/83377933