日期: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
