/* * Copyright 2007 Tom Gibara * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.jgrasstools.gears.utils.clustering; import java.util.Arrays; /** * Maintains a heap of cluster pairs. * * @author Tom Gibara * * @param <K> the key type */ class GvmClusterPairs<S extends GvmSpace, K> { private GvmClusterPair<S,K>[] pairs; private int size; @SuppressWarnings("unchecked") GvmClusterPairs(int initialCapacity) { pairs = new GvmClusterPair[initialCapacity]; size = 0; } GvmClusterPairs(GvmClusterPairs<S,K> that) { pairs = Arrays.copyOf(that.pairs, that.size); size = pairs.length; } public boolean add(GvmClusterPair<S,K> e) { if (e == null) throw new IllegalArgumentException("null pair"); int i = size; if (i >= pairs.length) grow(i + 1); size = i + 1; if (i == 0) { pairs[0] = e; e.index = 0; } else { heapifyUp(i, e); } return true; } public GvmClusterPair<S,K> peek() { return size == 0 ? null : pairs[0]; } public boolean remove(GvmClusterPair<S,K> pair) { int i = indexOf(pair); if (i == -1) return false; removeAt(i); return true; } public void reprioritize(GvmClusterPair<S,K> pair) { int i = indexOf(pair); if (i == -1) throw new IllegalArgumentException("no such pair"); pair.update(); GvmClusterPair<S,K> parent = i == 0 ? null : pairs[ (i - 1) >>> 1 ]; if (parent != null && parent.value > pair.value) { heapifyUp(i, pair); } else { heapifyDown(i, pair); } } public int size() { return size; } public void clear() { for (int i = 0; i < size; i++) { GvmClusterPair<S,K> e = pairs[i]; e.index = -1; pairs[i] = e; } size = 0; } private void grow(int minCapacity) { if (minCapacity < 0) throw new IllegalStateException("can't grow, maximum number of elements exceeded"); int oldCapacity = pairs.length; int newCapacity = ((oldCapacity < 64)? ((oldCapacity + 1) * 2): ((oldCapacity / 2) * 3)); if (newCapacity < 0) newCapacity = Integer.MAX_VALUE; if (newCapacity < minCapacity) newCapacity = minCapacity; pairs = Arrays.copyOf(pairs, newCapacity); } private int indexOf(GvmClusterPair<S,K> pair) { return pair == null ? -1 : pair.index; } private GvmClusterPair<S,K> removeAt(int i) { int s = --size; if (s == i) { // removing last element pairs[i].index = -1; pairs[i] = null; } else { GvmClusterPair<S,K> moved = pairs[s]; pairs[s] = null; moved.index = -1; heapifyDown(i, moved); if (pairs[i] == moved) { heapifyUp(i, moved); if (pairs[i] != moved) return moved; } } return null; } private void heapifyUp(int k, GvmClusterPair<S,K> pair) { while (k > 0) { int parent = (k - 1) >>> 1; GvmClusterPair<S,K> e = pairs[parent]; if (pair.value >= e.value) break; pairs[k] = e; e.index = k; k = parent; } pairs[k] = pair; pair.index = k; } private void heapifyDown(int k, GvmClusterPair<S,K> pair) { int half = size >>> 1; while (k < half) { int child = (k << 1) + 1; GvmClusterPair<S,K> c = pairs[child]; int right = child + 1; if (right < size && c.value > pairs[right].value) c = pairs[child = right]; if (pair.value <= c.value) break; pairs[k] = c; c.index = k; k = child; } pairs[k] = pair; pair.index = k; } }