/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.opentripplanner.common; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.opentripplanner.util.MapUtils; /** basic union-find data structure with path compression */ public class DisjointSet<T> { ArrayList<Integer> sets = new ArrayList<Integer>(); HashMap<T, Integer> setMapping = new HashMap<T, Integer>(); public DisjointSet() {} public int union(T element1, T element2) { Integer p1 = find(element1); Integer p2 = find(element2); if (p1.equals(p2)) { return p1; } int p1size = -sets.get(p1); int p2size = -sets.get(p2); int totalSize = p1size + p2size; if (p1size > p2size) { sets.set(p2, p1); sets.set(p1, -totalSize); return p2; } else { sets.set(p1, p2); sets.set(p2, -totalSize); return p1; } } public int find(T element) { Integer i = setMapping.get(element); if (i == null) { setMapping.put(element, sets.size()); sets.add(-1); return sets.size() -1; } return compact(i); } public boolean exists(T element) { return setMapping.containsKey(element); } public List<Set<T>> sets() { HashMap<Integer, Set<T>> out = new HashMap<Integer, Set<T>>(); for (Map.Entry<T, Integer> entry : setMapping.entrySet()) { MapUtils.addToMapSet(out, compact(entry.getValue()), entry.getKey()); } return new ArrayList<Set<T>>(out.values()); } private int compact(int i) { int key = sets.get(i); if (key < 0) { return i; } int j = compact(key); sets.set(i, j); return j; } public int size(int component) { return -sets.get(component); } }