日期:2020.03.24
博客期:168
星期二
【博客前言】
众所周不知啊,我在上大一的时候,进入了我们学校的ACM-算法竞赛协会,当时学习的成员还不多,但是学习氛围很好,我上的第一堂课就是关于并查集的使用,我就用当时才学完的 C语言实现了。我对于这个算法可以说是记忆犹新吧!这个例子我学了C++以后也实现过,那么今天就轮到我使用 Java 在设计模式和最近新确定好的Java代码规范的基础下再来实现这个“并查集”算法!
【代码功能】
并查集的适用场景:在分散的许多结点中,人为的添加一些点到点的线,使其构成多条树(每条树对应一个分组),可以判定两个结点是否有线路可以流通、可以人为地将两个分组连接起来。
【实装代码】
com.bcj 包:
数字并查集类:
1 package com.bcj; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 // Readme: 7 // 8 // English Name: UnionCheckingSet Class 9 // Chinese Name: 数字并查集类 10 // 11 // Writen by NS-Studio in 2020-03-24 17:41 12 // 13 public class UnionCheckingSet{ 14 //----------------------<成员属性>----------------------// 15 // 16 //---[基本类型] 17 18 //最大长度 19 private int max_len; 20 21 //父节点集合 22 private List <Integer> self_list; 23 24 //父节点连线权值集合 25 private List <Integer> par_list; 26 27 //----------------------<成员方法>----------------------// 28 // 29 //---[配置方法] 30 31 //初始化 32 private void init() { 33 this.reset(); 34 } 35 36 //重新初始化 37 public void reset() { 38 // 初始化 长度 39 this.self_list = new ArrayList <Integer> (); 40 this.par_list = new ArrayList <Integer> (); 41 42 // 给 数据 加上 1 对 1 的索引 43 for(int i=0;i<this.max_len;++i) 44 { 45 this.self_list.add(i); 46 this.par_list.add(0); 47 } 48 } 49 50 // 51 //---[实用方法] 52 53 //查找根节点 54 public int find_root_code(int index) { 55 // 我们 获取 它的父节点 56 int tmp = this.self_list.get(index); 57 58 // 如果 父节点 是 它本身,说明 它就是 根节点 59 if(index == tmp) 60 return index; 61 // 否则 它的根节点 就是 它的 父节点的 根节点 62 else 63 return this.find_root_code(tmp); 64 } 65 66 //两个结点是否相互连接 67 public boolean is_linked(int index_1,int index_2) { 68 // 如果 两个结点 所对应的 根节点 相同,那么 我们认为 它们是在连在一起的 69 return this.find_root_code(index_1) == this.find_root_code(index_2); 70 } 71 72 //两个结点相互连接 73 public void unite_code(int index_1,int index_2) { 74 // 将 结点 由 它们各自的 根节点 代替 75 index_1 = this.find_root_code(index_1); 76 index_2 = this.find_root_code(index_2); 77 78 // 如果 这两个结点 不在同一组内, 则将 根节点 相连 79 if(index_1!=index_2) 80 { 81 // 准备 权值信息 储存器 82 int par_1,par_2; 83 84 // 储存器 赋值 85 par_1 = this.par_list.get(index_1); 86 par_2 = this.par_list.get(index_2); 87 88 // 储存器值 高的 一方 作为 根节点 89 if(par_1 < par_2) 90 { 91 this.self_list.set(index_1,index_2); 92 } 93 // 如果 储存器值 相等 ,则 需要 轻微 调高 作为 根结点的 储存器值(不等不强制) 94 else 95 { 96 this.self_list.set(index_2,index_1); 97 this.par_list.set(index_1, par_1 + 1); 98 } 99 } 100 } 101 102 // 103 //---[构造方法] 104 105 //无参构造 : 参数 max_len 默认值为 1010 106 public UnionCheckingSet() { 107 super(); 108 // 无参的 设置默认值 109 this.max_len = 1010; 110 this.init(); 111 } 112 113 //单参构造 114 public UnionCheckingSet(int max_len) { 115 super(); 116 // 单参的 设置 max_len 值 117 this.max_len = max_len; 118 this.init(); 119 } 120 121 // 122 //---[测试方法] 123 124 // ----- 125 // 主方法 126 // 127 // 测试用例 : 128 // 分成三组——(1,3,4,6),(2,7),(5) 129 // 测试 1,3 和 2,5 分别 是否处在同一组 130 public static void main(String[] args) { 131 // 实例化 一个 并查集 对象 132 UnionCheckingSet ucs = new UnionCheckingSet(); 133 134 // 定义 一个 变量 :用于 存储 boolean 数据 135 boolean is = false; 136 137 // 连接对象 分组 138 // ---[A组] 139 ucs.unite_code(1,3); 140 ucs.unite_code(3,4); 141 ucs.unite_code(1,6); 142 // ---[B组] 143 ucs.unite_code(2,7); 144 145 // 测试 1,3 是否在同一组 146 // ---[改数值] 147 is = ucs.is_linked(1,3); 148 // ---[数据查看] 149 System.out.println(is); 150 151 // 测试 2,5 是否在同一组 152 // ---[改数值] 153 is = ucs.is_linked(2,5); 154 // ---[数据查看] 155 System.out.println(is); 156 } 157 }
并查集类:
1 package com.bcj; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 // Readme: 7 // 8 // English Name: MapCheckingSet Class 9 // Chinese Name: 并查集类 10 // 11 // Writen by NS-Studio in 2020-03-24 18:35 12 // 13 public class MapCheckingSet <T>{ 14 //----------------------<成员属性>----------------------// 15 // 16 //---[基本类型] 17 18 //最大长度 19 private int max_len; 20 21 //数据列表 22 private List <T> map_data; 23 24 //并查集 25 private UnionCheckingSet ucs; 26 27 //----------------------<成员方法>----------------------// 28 // 29 //---[配置方法] 30 31 //初始化 32 private void init() { 33 this.reset(); 34 } 35 36 //重新初始化 37 public void reset() { 38 // 初始化 长度 39 this.ucs = new UnionCheckingSet(this.max_len); 40 41 // 初始化 数据表 42 this.map_data = new ArrayList<T>(); 43 } 44 45 // 46 //---[实用方法] 47 48 //添加结点 49 public void add_code(T code_been_added) { 50 // 如果 表中 没有,就 加进去 51 if(!this.map_data.contains(code_been_added)) 52 this.map_data.add(code_been_added); 53 } 54 55 //查找结点的 index 56 private int index_of_list(T code_been_selected) { 57 // 位置 信息 索引 58 return this.map_data.indexOf(code_been_selected); 59 } 60 61 //两个结点是否相互连接 62 public boolean is_linked(T code_1,T code_2) { 63 // this.index_of_list( index ) 是 list 中的索引地址 64 int index_1 = this.index_of_list(code_1); 65 int index_2 = this.index_of_list(code_2); 66 67 // 根据 实际的值 调用 数值型 并查集 68 return this.ucs.is_linked(index_1, index_2); 69 } 70 71 //两个结点相互连接 72 public void unite_code(T code_1,T code_2) { 73 // this.index_of_list( index ) 是 list 中的索引地址 74 int index_1 = this.index_of_list(code_1); 75 int index_2 = this.index_of_list(code_2); 76 77 // 根据 实际的值 调用 数值型 并查集 78 this.ucs.unite_code(index_1, index_2); 79 } 80 81 // 82 //---[构造方法] 83 84 //无参构造 : 参数 max_len 默认值为 1010 85 public MapCheckingSet() { 86 super(); 87 // 无参的 设置默认值 88 this.max_len = 1010; 89 this.init(); 90 } 91 92 //单参构造 93 public MapCheckingSet(int max_len) { 94 super(); 95 // 单参的 设置 max_len 值 96 this.max_len = max_len; 97 this.init(); 98 } 99 100 // 101 //---[测试方法] 102 103 // ----- 104 // 主方法 105 // 106 // 测试用例 : 107 // 分成三组——(“李法”,“刘汉”,“王旺教”),(“孟兴”,“陶保”),(“田冒”,“赵埔彤”) 108 // 测试 “李法”,“刘汉” 和 “孟兴”,“田冒” 分别 是否处在同一组 109 public static void main(String[] args) { 110 // 实例化 一个 并查集 对象 111 MapCheckingSet <String> mcs = new MapCheckingSet<String>(); 112 113 // 定义 一个 变量 :用于 存储 boolean 数据 114 boolean is = false; 115 116 //加入数据 117 mcs.add_code("李法"); 118 mcs.add_code("刘汉"); 119 mcs.add_code("王旺教"); 120 mcs.add_code("孟兴"); 121 mcs.add_code("陶保"); 122 mcs.add_code("田冒"); 123 mcs.add_code("赵埔彤"); 124 125 // 连接对象 分组 126 // ---[A组] 127 mcs.unite_code("李法","刘汉"); 128 mcs.unite_code("刘汉","王旺教"); 129 // ---[B组] 130 mcs.unite_code("孟兴","陶保"); 131 // ---[C组] 132 mcs.unite_code("田冒","赵埔彤"); 133 134 // 测试 “李法”,“刘汉” 是否在同一组 135 // ---[改数值] 136 is = mcs.is_linked("李法","刘汉"); 137 // ---[数据查看] 138 System.out.println(is); 139 140 // 测试 “孟兴”,“田冒” 是否在同一组 141 // ---[改数值] 142 is = mcs.is_linked("孟兴","田冒"); 143 // ---[数据查看] 144 System.out.println(is); 145 } 146 }
【项目结构图】
【类图】
目前就两个类,实际上没什么看点
【使用到的设计模式】
1、模板方法模式:并查集的算法部分是模板方法(可以套用)
2、适配器模式:这次还是隐式的对象适配器模式,把 UnionChckingSet 作为 对象成员 ,数据表成员 是伪子类!
【测试】
由于代码中测试信息较为详细,博主在这里不过多摄入。
来源:https://www.cnblogs.com/onepersonwholive/p/12561733.html