001 /* 002 * LAPIS lightweight structured text processing system 003 * 004 * Copyright (C) 1998-2002 Carnegie Mellon University, 005 * Copyright (C) 2003 Massachusetts Institute of Technology. 006 * All rights reserved. 007 * 008 * This library is free software; you can redistribute it 009 * and/or modify it under the terms of the GNU General 010 * Public License as published by the Free Software 011 * Foundation, version 2. 012 * 013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/ 014 */ 015 016 017 package lapisx.util; 018 019 import java.util.Enumeration; 020 import java.util.Vector; 021 022 /** 023 * Priority queue. Objects stored in a priority queue must implement 024 * the Prioritized interface. 025 * 026 */ 027 public class PriorityQueue { 028 029 private Vector q; // the queue of elements 030 031 /** 032 * Make an empty PriorityQueue. 033 */ 034 public PriorityQueue () { 035 q = new Vector (); 036 } 037 038 /** 039 * Make an empty PriorityQueue with an initial capacity. 040 * @param initialCapacity number of elements initially allocated in queue 041 */ 042 public PriorityQueue (int initialCapacity) { 043 q = new Vector (initialCapacity); 044 } 045 046 /** 047 * Put an object on the queue. Doesn't check for 048 * duplicate puts. 049 * @param x object to put on the queue 050 */ 051 public synchronized void put (Prioritized x) { 052 int newSize = q.size()+1; 053 q.setSize (newSize); 054 float priorityX = x.getPriority (); 055 056 int i, p; 057 for (i=newSize-1, p = ((i+1)/2)-1; // i's parent 058 i > 0 && getPriority (p) > priorityX; 059 i = p, p = ((i+1)/2)-1) 060 q.setElementAt (q.elementAt (p), i); 061 062 q.setElementAt (x, i); 063 } 064 065 /** 066 * Get object with lowest priority from queue. 067 * @return object with lowest priority, or null if queue is empty 068 */ 069 public synchronized Object getMin () { 070 return !empty() ? q.elementAt (0) : null; 071 } 072 073 /** 074 * Get and delete the object with lowest priority. 075 * @return object with lowest priority, or null if queue is empty 076 */ 077 public synchronized Object deleteMin () { 078 if (empty()) 079 return null; 080 Object obj = q.elementAt (0); 081 deleteElement (0); 082 return obj; 083 } 084 085 /** 086 * Delete an object from queue. If object was inserted more than 087 * once, this method deletes only one occurrence of it. 088 * @param x object to delete 089 * @return true if x was found and deleted, false if x not found in queue 090 */ 091 public synchronized boolean delete (Prioritized x) { 092 int i = q.indexOf (x); 093 if (i == -1) 094 return false; 095 deleteElement (i); 096 return true; 097 } 098 099 /** 100 * Remove all objects from queue. 101 */ 102 public synchronized void clear () { 103 q.removeAllElements (); 104 } 105 106 107 /** 108 * Enumerate the objects in the queue, in no particular order 109 * @return enumeration of objects in queue 110 */ 111 public synchronized Enumeration elements () { 112 return q.elements (); 113 } 114 115 116 /** 117 * Get number of objects in queue. 118 * @return number of objects 119 */ 120 public synchronized int size () { 121 return q.size (); 122 } 123 124 125 /** 126 * Test whether queue is empty. 127 * @return true iff queue is empty. 128 */ 129 public synchronized boolean empty () { 130 return q.isEmpty (); 131 } 132 133 /** 134 * Rebuild priority queuein case the priorities of its elements 135 * have changed since they were inserted. If the priority of 136 * any element changes, this method must be called to update 137 * the priority queue. 138 */ 139 public synchronized void update () { 140 for (int i = (q.size()/2) - 1; i >= 0; --i) 141 heapify (i); 142 } 143 144 final void deleteElement (int i) { 145 int last = q.size()-1; 146 q.setElementAt (q.elementAt (last), i); 147 q.setElementAt (null, last); // avoid holding extra reference 148 q.setSize (last); 149 heapify (i); 150 } 151 152 /* Establishes the heap property at i's descendents. 153 */ 154 final void heapify (int i) { 155 int max = q.size(); 156 while (i < max) { 157 int r = 2*(i+1); // right child of i 158 int l = r - 1; // left child of i 159 160 int smallest = i; 161 float prioritySmallest = getPriority (i); 162 float priorityR; 163 164 if (r < max && (priorityR = getPriority (r)) < prioritySmallest) { 165 smallest = r; 166 prioritySmallest = priorityR; 167 } 168 if (l < max && getPriority (l) < prioritySmallest) { 169 smallest = l; 170 } 171 172 if (smallest != i) { 173 swap (i, smallest); 174 i = smallest; 175 } 176 else 177 break; 178 } 179 } 180 181 /* Swap elements at positions i and j in the table. 182 */ 183 final void swap (int i, int j) { 184 Object tmp = q.elementAt (i); 185 q.setElementAt (q.elementAt (j), i); 186 q.setElementAt (tmp, j); 187 } 188 189 /* Return the priority of the element at position i. For convenience, 190 positions beyond the end of the table have infinite priority. 191 */ 192 final float getPriority (int i) { 193 return ((Prioritized)q.elementAt (i)).getPriority(); 194 } 195 196 public static void main (String[] args) { 197 PriorityQueue q = new PriorityQueue (); 198 199 for (int i=0; i<args.length; ++i) { 200 float f = Float.valueOf (args[i]).floatValue(); 201 q.put (new PQItem (f)); 202 System.out.println ("put (" + f + ")"); 203 } 204 205 System.out.println ("getMin() = " + q.getMin()); 206 System.out.println ("empty() = " + q.empty()); 207 208 dump (q); 209 210 if (q.size() > 0) { 211 Enumeration enum = q.elements (); 212 for (int j=0; j<q.size()/2; ++j) 213 enum.nextElement(); 214 215 PQItem deletable = (PQItem)enum.nextElement(); 216 q.delete (deletable); 217 System.out.println ("delete (" + deletable + ")"); 218 219 dump (q); 220 } 221 222 float last = Float.NEGATIVE_INFINITY; 223 PQItem item; 224 while ((item = (PQItem)q.deleteMin()) != null) { 225 System.out.println ("deleteMin() = " + item); 226 if (item.getPriority() < last) 227 System.out.println ("ERROR! greater than last == " + last); 228 last = item.getPriority (); 229 dump (q); 230 } 231 } 232 233 public static void dump (PriorityQueue q) { 234 Enumeration enum = q.elements (); 235 for (int j=0; enum.hasMoreElements(); ++j) { 236 System.out.println ("elements()[" + (j+1) + "] = " + enum.nextElement()); 237 } 238 } 239 } 240 241 // used for testing only (see main() above) 242 class PQItem implements Prioritized { 243 float priority; 244 245 public PQItem (float priority) { 246 this.priority = priority; 247 } 248 249 public float getPriority () { 250 return priority; 251 } 252 253 public String toString () { 254 return String.valueOf (priority); 255 } 256 }