问题描述:java
如上图,给定一个数组,size = N ,若是 p 和 q 的 id 相等则 p 和 q 连通算法
对象连通的特性:数组
一、自反性:p 恒定连通 p 自身。测试
二、对称性:若是 p 连通 q ,则 q 连通 p 。ui
三、传递性:若是 p 连通 q ,q 连通 r ,则 p 连通 r 。code
这里简单运用对数组 id[] 的访问(读或写)次数去考虑采用 quick-find 算法的时间复杂度。对象
算法类源码:blog
public class QuickFindUF { private int[] id; public QuickFindUF(int size) { id = new int[size]; for (int i = 0; i < size; 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++) { if (id[i] == pid) { id[i] = qid; } } } public String toString() { //这里为了方便观看数组的变化,我重写了 toString() 方法 String temp = "["; for (int i = 0; i < id.length; i++) { if (i == id.length - 1) { temp += id[i] + "]"; break; } temp += id[i] + ", "; } return temp; } }
测试类源码(附带算法时间复杂度分析):源码
public class TestQuickFind { public static void main(String[] args) { QuickFindUF qf = new QuickFindUF(10); //访问(读或写)id[] 10次(N) qf.union(5, 0); //访问id[] 10 + 2 次 System.out.println(qf); //结果:[0, 1, 2, 3, 4, 0, 6, 7, 8, 9] qf.union(6, 5); //访问id[] 10 + 2 次 System.out.println(qf); //结果:[0, 1, 2, 3, 4, 0, 0, 7, 8, 9] //到此已链接了0, 5, 6三个整数(对象),总共访问id[](2 + 1) * (10 + 2)次(3N) //若链接0, 5, 6, 9四个整数(对象),以下: qf.union(9, 6); //访问id[] 10 + 2 次 //总共是(3 + 1) * (10 + 2) 次(4N) //因此往下推导将N个对象链接起来, //至少须要访问(N - 1)*(N + 2)+ N = N * N + 2N - 2 = (N + 1)*(N + 1)- 3 次id[] System.out.println(qf.connected(6, 0)); //connected访问id[] 2次 } }
须要注意的是:io
链接 N 个对象只须要 N - 1 次 union,访问数组(N - 1)*(N + 2)次 。new QuickFindUF(N) 是访问数组 N 次。因此二者相加,总共访问数组:(N - 1)*(N + 2)+ N = (N + 1)*(N + 1)- 3 次
能够看到,connected() 的时间复杂度是 O(1) ,当调用 n 次此方法,则时间复杂度为增为 O(n) ;union() 的时间复杂度为 O(n) ,若调用 n 次此方法,则复杂度变为 O(n * n) (2次方打不出来,很差意思哈)。
在 main 方法里的测试代码整体时间复杂度是 O(n * n) 级别的,即 quick-find 算法的查找对象并检查两个对象是否连通(connected())的速度是很快的(O(1) ~ O(n)),属于线性增加;可执行 union() 时,速度不尽如人意,时间复杂度属于幂增加,以目前计算机硬件的运算水准来看是较为消耗运算时间的一种算法。