Java 樹的構造算法

連通的定義:從A定點出發能到達B定點,則稱A-B連通

連通的基本性質:

  • 自反性:A一定連通A(ps:自己可以和自己PY交易)
  • 對稱性:如果A和B連通,則B和A也連通(無向的情況下)
  • 傳遞性:如果A連通B,B連通C,則A連通C

樹:

  • 大小(size):樹的節點數量
  • 深度(depth):某個節點到根節點的鏈接路徑的數量
  • 高度(height):樹所有節點中深度最大的值

森林的構造(目標:深度儘量小,樹儘量少):

  • quick-find
  • quick-union
  • 加權quick-union
  • 路徑壓縮

實現

  • quick-find算法(所有具有連通關係的觸點都指向終觸點,查找觸點很快,但連通觸點較慢)

class UF {
	int[] id;
	int count;

	UF(int N) {
		id = new int[N];
		count = N;
	}
        
        //將所有連通觸點指向最後的觸點


        int find(int p) {
		return id[p];
	}

	void union(int p, int q) {
		int pID = find(p);//獲取起觸點
		int qID = find(q);//獲取終觸點

		if (pID == qID) {//如果已經連通,結束
			return;
		}
		for (int i = 0; i < id.length; i++) {//遍歷所有觸點
			if (id[i] == pID) {//如果有觸點指向起觸點,說明起觸點之前已經和其他觸點連接
				id[i] = qID; //將所有指向起觸點的觸點指向終觸點
				count--;//連通數量減一
			}
		}
	}

	
	boolean connection(int p, int q) {
		return id[p] == id[q];
	}

	int count() {
		return count;
	}

}
  • quick-union(所有具有連通關係的觸點都指向自己的終觸點,連通觸點很快,但查找觸點較慢)
class UF1 {
	int[] id;
	int count;

	UF1(int N) {
		id = new int[N];
		count = N;
	}

        
        //查找觸點的根觸點,類似遞歸回溯
        int find(int p) {
		while(p!=id[p]) p = id[p];
		return id[p];
	}

	void union(int p, int q) {
		int pRoot = find(p);
		int qRoot = find(q);

		if (pRoot == qRoot) {
			return;
		}
		id[pRoot] = qRoot;//直接將新節點指向根節點
	}

	

	boolean connection(int p, int q) {
		return id[p] == id[q];
	}

	int count() {
		return count;
	}

}

 

  •  加權quick-union(在quick-union的基礎上將小樹掛在根節點上,而不是掛在子樹上,減少了數的深度,最常用)
package chapter1_5;

/**
 * @author : jeasion
 * @name
 * @comment
 * @return
 */
public class WeightQuickUnion {
	int[] id;
	int count;
	int[] size;

	public WeightQuickUnion(int N) {
		id = new int[N];
		size = new int[N];
		count = N;
		for (int i = 0; i < id.length; i++) {
			id[i] = i;
			size[i] = 1;
		}

	}

	void union(int p, int q) {
		int pRoot = find(p);
		int qRoot = find(q);

		if (pRoot == qRoot) {
			return;
		}
        //如果p樹的size小於q樹的size,說明q樹比p樹大,則將p樹掛到p樹上
		if (size[pRoot] <= size[qRoot]) {
	//將p樹的根節點qRoot賦給q樹的根節點,使q樹成爲p樹根節點的直接子節點
                        id[pRoot] = qRoot;
			size[qRoot] += size[pRoot];
		} else {
			id[qRoot] = pRoot;
			size[qRoot] += size[pRoot];
		}
	}

	int find(int p) {
		while (p != id[p])
			p = id[p];
		return id[p];
	}

	boolean connection(int p, int q) {
		return id[p] == id[q];
	}

	int count() {
		return count;
	}

}
  • 路徑壓縮(將所有節點鏈接到一個根節點,樹上完全扁平的,所有節點的深度都是1,樹的高度也爲1)

實現:在查找find()的同時直接將節點鏈接到根節點,最優算法(PS:我也不知道爲啥好像不實用)

 

圖解:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章