java算法事例:连通性
假设现在一个整数对序列,每个整数代表某种类型的对象,用p-q对表示“p连接到q”,又假设连接具有传递性,即p连接到q,q连接到r,则p连接到r。
例一:解决连通性问题的快速查找算法
- publicclassQuickF{
- publicstaticvoidmain(String[]args){
- intN=10;
- intid[]=newint[N];
- for(inti=0;i<N;i++){
- id[i]=i;
- }
- int[][]a=newint[][]{
- {3,4},{4,9},{8,0},{2,3},{0,2},{5,6},
- {2,9},{5,9},{7,3},{4,8},{5,6},{6,1}
- };
- System.out.println(Arrays.toString(id));
- for(int[]s:a){
- intp=s[0],q=s[1];
- intt=id[p];
- if(t==id[q]){
- continue;
- }
- for(inti=0;i<N;i++){
- if(id[i]==t){
- id[i]=id[q];
- System.out.println(""+p+""+q);
- System.out.println(Arrays.toString(id));
- }
- }
- }
- }
- }
public class QuickF {
public static void main(String[] args) {
int N = 10;
int id [] = new int[N];
for(int i = 0; i < N; i++){
id[i] = i;
}
int [] [] a = new int [][]{
{3,4},{4,9},{8,0},{2,3},{0,2},{5,6},
{2,9},{5,9},{7,3},{4,8},{5,6},{6,1}
};
System.out.println(Arrays.toString(id));
for(int [] s : a){
int p = s[0], q = s[1];
int t = id[p];
if(t == id[q]){
continue;
}
for(int i = 0; i < N; i++){
if(id[i] == t){
id[i] = id[q];
System.out.println(" " + p + " " + q);
System.out.println(Arrays.toString(id));
}
}
}
}
}
在用快速查找算法时,对序列{p,q}每一对进行处理后,id数组中的值为合并操作。把所有与id[p]值相同的元素值变为id[q]值。
例二:快速合并(并不快速的查找)
- publicclassQuickFU{
- publicstaticvoidmain(String[]args){
- intN=10;
- intid[]=newint[N];
- for(inti=0;i<N;i++){
- id[i]=i;
- }
- int[][]a=newint[][]{
- {3,4},{4,9},{8,0},{2,3},{5,6},{2,9},
- {5,9},{7,3},{4,8},{5,6},{0,2},{6,1},{5,8}
- };
- System.out.println(Arrays.toString(id));
- for(int[]s:a){
- inti,j,p=s[0],q=s[1];
- for(i=p;i!=id[i];i=id[i]);
- for(j=q;j!=id[j];j=id[j]);
- if(i==j){
- continue;
- }
- id[i]=j;
- System.out.println(""+p+""+q);
- System.out.println(Arrays.toString(id));
- }
- }
- }
public class QuickFU {
public static void main(String[] args) {
int N = 10;
int id [] = new int[N];
for(int i = 0; i < N; i++){
id[i] = i;
}
int [] [] a = new int [][]{
{3,4},{4,9},{8,0},{2,3},{5,6},{2,9},
{5,9},{7,3},{4,8},{5,6},{0,2},{6,1},{5,8}
};
System.out.println(Arrays.toString(id));
for(int [] s : a){
int i, j, p = s[0], q = s[1];
for(i = p; i != id[i]; i = id[i]);
for(j = q; j != id[j]; j = id[j]);
if(i == j){
continue;
}
id [i] = j;
System.out.println(" " + p + " " + q);
System.out.println(Arrays.toString(id));
}
}
}
在快速查找算法中,只需经过一个连接就可以找到节点;而在快速合并中中,可能需要多个节点才能找到。
例三:快速合并的加权版本
- publicclassQuickFW{
- publicstaticvoidmain(String[]args){
- intN=10;
- intid[]=newint[N];
- intsz[]=newint[N];
- for(inti=0;i<N;i++){
- id[i]=i;
- sz[i]=1;
- }
- int[][]a=newint[][]{
- {3,4},{4,9},{8,0},{2,3},{5,6},{2,9},
- {5,9},{7,3},{4,8},{5,6},{0,2},{6,1}
- };
- System.out.println(Arrays.toString(id));
- for(int[]s:a){
- inti,j,p=s[0],q=s[1];
- for(i=p;i!=id[i];i=id[i]);
- for(j=q;j!=id[j];j=id[j]);
- if(i==j){
- continue;
- }
- if(sz[i]<sz[j]){
- id[i]=j;
- sz[j]+=sz[i];
- }else{
- id[j]=i;
- sz[i]+=sz[j];
- }
- System.out.println(""+p+""+q);
- System.out.println(Arrays.toString(id));
- System.out.println(Arrays.toString(sz));
- }
- }
- }
public class QuickFW {
public static void main(String[] args) {
int N = 10;
int id [] = new int[N];
int sz [] = new int[N];
for(int i = 0; i < N; i++){
id[i] = i;
sz[i] = 1;
}
int [] [] a = new int [][]{
{3,4},{4,9},{8,0},{2,3},{5,6},{2,9},
{5,9},{7,3},{4,8},{5,6},{0,2},{6,1}
};
System.out.println(Arrays.toString(id));
for(int [] s : a){
int i, j, p = s[0], q = s[1];
for(i = p; i != id[i]; i = id[i]);
for(j = q; j != id[j]; j = id[j]);
if(i == j){
continue;
}
if(sz[i] < sz[j]){
id[i] = j;
sz[j] += sz[i];
}else{
id[j] = i;
sz[i] += sz[j];
}
System.out.println(" " + p + " " + q);
System.out.println(Arrays.toString(id));
System.out.println(Arrays.toString(sz));
}
}
}
加权快速合并算法在典型情况下,可以在线性时间内解决实际问题。
路径压缩,在合并操作中,经过每条路径就加一条连线,把一路上遇到的对应的每个顶点的id数组值都设为到树根上,逼近了快速查找算法的理想状态。
例四:压缩方法:使在通向树根的路中的每条连线都指向路劲中的下一个节点,即折半路径压缩的加权快速合并
- publicclassQuickFH{
- publicstaticvoidmain(String[]args){
- intN=10;
- intid[]=newint[N];
- intsz[]=newint[N];
- for(inti=0;i<N;i++){
- id[i]=i;
- sz[i]=1;
- }
- int[][]a=newint[][]{
- {3,4},{4,9},{8,0},{2,3},{5,6},{2,9},
- {5,9},{7,3},{4,8},{5,6},{0,2},{6,1}
- };
- System.out.println(Arrays.toString(id));
- for(int[]s:a){
- inti,j,p=s[0],q=s[1];
- for(i=p;i!=id[i];i=id[i]){
- id[i]=id[id[i]];
- }
- for(j=q;j!=id[j];j=id[j]){
- id[j]=id[id[j]];
- }
- if(i==j){
- continue;
- }
- if(sz[i]<sz[j]){
- id[i]=j;
- sz[j]+=sz[i];
- }else{
- id[j]=i;
- sz[i]+=sz[j];
- }
- System.out.println(""+p+""+q);
- System.out.println(Arrays.toString(id));
- System.out.println(Arrays.toString(sz));
- }
- }
- }
public class QuickFH {
public static void main(String[] args) {
int N = 10;
int id [] = new int[N];
int sz [] = new int[N];
for(int i = 0; i < N; i++){
id[i] = i;
sz[i] = 1;
}
int [] [] a = new int [][]{
{3,4},{4,9},{8,0},{2,3},{5,6},{2,9},
{5,9},{7,3},{4,8},{5,6},{0,2},{6,1}
};
System.out.println(Arrays.toString(id));
for(int [] s : a){
int i, j, p = s[0], q = s[1];
for(i = p; i != id[i]; i = id[i]){
id[i] = id[id[i]];
}
for(j = q; j != id[j]; j = id[j]){
id[j] = id[id[j]];
}
if(i == j){
continue;
}
if(sz[i] < sz[j]){
id[i] = j;
sz[j] += sz[i];
}else{
id[j] = i;
sz[i] += sz[j];
}
System.out.println(" " + p + " " + q);
System.out.println(Arrays.toString(id));
System.out.println(Arrays.toString(sz));
}
}
}
得到的与例三一样的净结果,比全路径压缩算法更简单。
通过一系列的算法:找到了解决实际问题的好算法,它比较容易实现,且运行实际保证在收集数据项所花费时间的常数因子范围内。在这些算法中需要仔细和复杂的分析,才能找到最优算法。