/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library 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; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.graph.util; import java.lang.reflect.Array; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.NoSuchElementException; public class PriorityQueue implements Collection, Queue { public static double RESIZE_FACTOR = 1.5; private Comparator m_comparator = null; private Object[] m_values = null; private int m_count = 0; private HashMap m_obj2index = null; public PriorityQueue(Comparator comparator) { m_comparator = comparator; m_obj2index = new HashMap(); } public void init(int size) { if (m_values == null || size > m_values.length) resize(size+1, false); for (int i = 0; i < m_values.length; i++) { m_values[i] = null; } m_count = 0; } public void insert(Object value) { ++m_count; if (m_count >= m_values.length) resize((int)(m_values.length*RESIZE_FACTOR), true); m_values[m_count] = value; m_obj2index.put(value, new Integer(m_count)); moveUp(m_count); } public Object extract() { if (m_count == 0) throw new NoSuchElementException("Heap empty."); Object value = m_values[1]; swap(1, m_count); m_values[m_count--] = null; moveDown(1); m_obj2index.remove(value); return(value); } public Object getRoot() { if (m_count == 0) throw new NoSuchElementException("Heap Empty."); return(m_values[1]); } public void update() { int n = (int)size()/2; for (int i = 1; i <= n; i++) { update(i); } } public int update(int i) { //check parent, if value is less, propogate value up if (i > 1 && compare(i, i/2) < 0) { return(moveUp(i)); } //check children, if value more, propogate value down if ((2*i <= size() && compare(i, 2) > 0) || (2*i+1 <= size() && compare(i, 2*i+1) > 0)) { return(moveDown(i)); } return(i); } public void update(Object value) { Integer index = ((Integer)m_obj2index.get(value)); if (index == null) { for (int i = 1; i < m_count; i++) { Object o = (Object)m_values[i]; if (o == value) System.out.println(); } } update(index.intValue()); //TODO: improve performance, dont use a linear search // for (int i = 1; i < m_values.length; i++) { // if (m_values[i] == value) { // update(i); // return; // } // } } public boolean isEmpty() { return(m_count == 0); } public int size() { return(m_count); } private int moveDown(int n) { int minchild = 0; if(2*n <= m_count) { minchild = 2*n; if (2*n + 1 <= m_count) { minchild = (compare(2*n, 2*n + 1) < 0) ? 2*n : 2*n + 1; } if (compare(minchild, n) < 0) { swap(minchild, n); return(moveDown(minchild)); } } return(n); } private int moveUp(int n) { int parent = (n % 2 == 0) ? n/2 : (n - 1)/2; if (parent > 0 && compare(n, parent) < 0) { swap(n, parent); return(moveUp(parent)); } return(n); } private int compare(int i, int j) { return(m_comparator.compare(m_values[i], m_values[j])); } private void resize(int size, boolean preserve) { Object[] resized = new Object[size]; if (preserve) { for (int i = 0; i < m_values.length && i < size; i++) { resized[i] = m_values[i]; } } m_values = resized; } /** TODO: DOCUMENT ME! Note that this method should be used cautiously **/ public void swap(int i, int j) { //first swap the reference to the indicies if (m_obj2index.get(m_values[i]) == null || m_obj2index.get(m_values[j]) == null) System.out.println(); Object tmp = m_obj2index.get(m_values[i]); m_obj2index.put(m_values[i], m_obj2index.get(m_values[j])); m_obj2index.put(m_values[j], tmp); //swap objects in array tmp = m_values[i]; m_values[i] = m_values[j]; m_values[j] = tmp; } public void clear() { init(0); } public Object[] toArray() { return(m_values); } public boolean add(Object o) { insert(o); return(true); } public Object get(int i) { if (i == 0 && i > m_count) return(null); return(m_values[i]); } public boolean contains(Object o) { for (int i = 0; i < m_values.length; i++) { if (m_values[i].equals(o)) return(true); } return(false); } public boolean remove(Object o) { //TODO: improve performance, dont use a linear search for (int i = 1; i < m_values.length; i++) { if (m_values[i] == o) { remove(i); return(true); } } return(false); } public void remove(int i) { //check to see if item is last in heap if (i < m_count) { //first do a swap with last element in heap swap(i, m_count); //remove last element m_values[m_count--] = null; //update previous last element update(i); } else { //simply remove the last element m_values[m_count--] = null; } } public boolean addAll(Collection c) { for (Iterator itr = c.iterator(); itr.hasNext();) { add(itr.next()); } return(true); } public boolean containsAll(Collection c) { for (Iterator itr = c.iterator(); itr.hasNext();) { if (!contains(itr.next())) return(false); } return(true); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException( "Heap#removeAll(Collection) not supported" ); } public boolean retainAll(Collection c) { throw new UnsupportedOperationException( "Heap#retainAll(Collection) not supported" ); } public Iterator iterator() { return( new Iterator() { int i = 1; public void remove() { throw new UnsupportedOperationException( "Iterator#remove() not supported" ); } public boolean hasNext() { return(i < m_values.length); } public Object next() { return(m_values[i++]); } } ); } public Object[] toArray(Object[] a) { if (a.length < m_values.length) a = (Object[])Array.newInstance( a.getClass().getComponentType(), m_values.length ); for (int i = 0; i < m_values.length; i++) { a[i] = m_values[i]; } if (a.length > m_values.length) a[m_values.length] = null; return(a); } //Queue implementation public Object deq() { return(extract()); } public void enq(Object object) { insert(object); } }