多个集合合并成没有交集的集合-实现
2012-08-14 17:50 coodoing 阅读(5216) 评论(1) 编辑 收藏 举报1、问题描述
将多个集合合并成没有交集的集合。
给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。
(1)请描述你解决这个问题的思路;
(2)请给出主要的处理流程,算法,以及算法的复杂度
(3)请描述可能的改进。
2、分析
1. 假定每个集合编号为0,1,2,3...
2. 创建一个hash_map,key为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。
3. 创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。开始时将所有值都初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。
遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。
4.现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。
0: {aaa bbb ccc}
1: {bbb ddd}
2: {eee fff}
3: {ggg}
4: {ddd hhh}
生成的hash_map,和处理完每个值后的合并关系数组分别为
aaa: 0
bbb: 0, 1
ccc: 0
ddd: 1, 4
eee: 2
fff: 2
ggg: 3
hhh: 4
所以合并完后有三个集合,第0,1,4个集合合并到了一起,
第2,3个集合没有进行合并。
3、具体实现
1: class DisjointSetProblem {
2: private final int SIZE = 7;
3: private int[] father;
4: private static List<Set<String>> resultList = new ArrayList<Set<String>>();
5:
6: public static void main(String[] args) {
7: String[] str0 = { "aaa", "bbb", "ccc", };
8: String[] str1 = { "bbb", "ddd", };
9: String[] str2 = { "eee", "fff", };
10: String[] str3 = { "ggg", };
11: String[] str4 = { "ddd", "hhh", };
12: String[] str5 = { "xx", "yy", };
13: String[] str6 = { "zz", "yy", };
14: String[][] strs = { str0, str1, str2, str3, str4, str5, str6 };
15: //change String[][] to List<Set>
16: for (String[] str : strs) {
17: //when I write--"Arraylist list=Arrays.asList(strArray)","addAll()" is unsupported for such a arraylist.
18: Set<String> set = new HashSet<String>();
19: set.addAll(Arrays.asList(str));
20: resultList.add(set);
21: }
22: DisjointSetProblem disjointSet = new DisjointSetProblem();
23: disjointSet.disjoin(strs);
24: }
25:
26: /*
27: * 获取hashmap过程
28: * */
29: public void disjoin(String[][] strings) {
30: if (strings == null || strings.length < 2)
31: return;
32: initial();
33: // 获得hash_map:key为字符串,value为一个链表
34: Map<String, List<Integer>> map = storeInHashMap(strings);
35: // 并查集进行合并
36: union(map);
37: }
38:
39: //in the beginning,each element is in its own "group".
40: public void initial() {
41: father = new int[SIZE];
42: for (int i = 0; i < SIZE; i++) {
43: father[i] = i;
44: }
45: }
46:
47: /* Map<k,v>
48: * key:String
49: * value:List<Integer>-in which sets the string shows up.
50: */
51: public Map<String, List<Integer>> storeInHashMap(String[][] strings) {
52: Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();
53: for (int i = 0; i < SIZE; i++) {
54: for (String each : strings[i]) {
55: if (!map.containsKey(each)) {
56: List<Integer> list = new ArrayList<Integer>();
57: list.add(i);
58: map.put(each, list);
59: } else {
60: map.get(each).add(i);
61: }
62: }
63: }
64:
65: // 打印出map
66: System.out.println("集合映射所生成的hashmap为:");
67: printMap(map);
68: return map;
69: }
70:
71: private void printMap(Map<String, List<Integer>> map) {
72: // TODO Auto-generated method stub
73: Iterator<Map.Entry<String, List<Integer>>> iter = map.entrySet()
74: .iterator();
75: while (iter.hasNext()) {
76: Map.Entry<String, List<Integer>> entry = iter.next();
77: String key = entry.getKey();
78: List<Integer> value = entry.getValue();
79: System.out.println(key + ":" + value);
80: }
81: System.out.println();
82: }
83:
84: /*
85: * 对hashmap进行并查集合并操作
86: * */
87: public void union(Map<String, List<Integer>> map) {
88: Iterator<Map.Entry<String, List<Integer>>> it = map.entrySet()
89: .iterator();
90: while (it.hasNext()) {
91: Map.Entry<String, List<Integer>> entry = it.next();
92: List<Integer> value = entry.getValue();
93: unionHelp(value);//the arrays whose indexes are in the same list should be merged to one set.
94: }
95: // 打印出father父节点信息
96: System.out.println("hashmap集合合并之后的父节点信息为:");
97: printFather(father);//System.out.println("the father array is " + Arrays.toString(father));
98: printSetList(resultList);
99: //merge two sets
100: for (int i = 0; i < SIZE; i++) {
101: if (i != father[i]) {
102: // set:无重复元素
103: Set<String> dest = resultList.get(father[i]);
104: Set<String> source = resultList.get(i);
105: dest.addAll(source);
106: }
107: }
108: //clear a set which has been added.
109: // 当B集合添加到A集合后,清空B集合
110: for (int i = 0; i < SIZE; i++) {
111: if (i != father[i]) {
112: resultList.get(i).clear();
113: }
114: }
115: System.out.println("合并后:" + resultList);
116: }
117:
118: public void unionHelp(List<Integer> list) {
119: int minFather = getFather(list.get(0));//list[0] is the smaller.
120: // 传过来的list参数已经排好序
121: for (int i = 0, size = list.size(); i < size; i++) {
122: //father[list.get(i)] = minFather;
123: unionHelp(list.get(0),list.get(i));
124: }
125: }
126:
127: // 路径压缩
128: public int getFather(int x) {
129: while (x != father[x]) {
130: x = father[x];
131: }
132: return x;
133: }
134:
135: private void printFather(int[] fatherNode) {
136: // TODO Auto-generated method stub
137: for (int node : fatherNode)
138: System.out.print(node + " ");
139: System.out.println();
140: }
141:
142: private void printSetList(List<Set<String>> list) {
143: // TODO Auto-generated method stub
144: System.out.print("合并前:");
145: for (int i = 0; i < SIZE; i++) {
146: System.out.print(list.get(i) + " ");
147: }
148: System.out.println();
149: }
150:
151: //general union in disjoin set.But we overload it in this case.
152: public void unionHelp(int x, int y) {
153: if (father[x] != father[y]) {
154: int fx = getFather(x);
155: int fy = getFather(y);
156: //merge two arrays to the array that has a smaller index.
157: if (fx < fy) {
158: father[y] = fx;
159: } else {
160: father[x] = fy;
161: }
162: }
163: }
164:
165: }