001 /* 002 NGramJ - n-gram based text classification 003 Copyright (C) 2001 Frank S. Nestel (frank at spieleck.de) 004 005 This program is free software; you can redistribute it and/or modify 006 it under the terms of the GNU Lesser General Public License as published 007 by the Free Software Foundation; either version 2.1 of the License, or 008 (at your option) any later version. 009 010 This program is distributed in the hope that it will be useful, 011 but WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 GNU General Public License for more details. 014 015 You should have received a copy of the GNU Lesser General Public License 016 along with this program (lesser.txt); if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 018 */ 019 020 package de.spieleck.util; 021 022 import java.util.Comparator; 023 024 /** A PriorityQueue maintains a partial ordering of its elements such that the 025 least element can always be found in constant time. 026 <P> 027 This is achieved by a heap implementation, therefore 028 Put()'s and pop()'s require log(size) time. Note that this heap is 029 realized by linear insertion and not by "bubbling". 030 <P> 031 This class can either be directly used by passing a 032 <code>java.util.Comparator</code> 033 object to the constructor, or by subclassing and overriding the 034 <code>lessThan()</code> method. 035 <P> 036 <B>XXX</B> This is an lazy implementation which spoils the very first 037 entry in the heap! 038 <P> 039 <B>Caution:</B>This class is unsynchronized and therefore 040 needs external synchronization in an multithreading environment. 041 */ 042 043 public class PriorityQueue 044 { 045 protected int size; 046 protected Object[] heap; 047 048 protected Comparator myComp; 049 050 public PriorityQueue(int initialSize, Comparator comp) 051 { 052 myComp = comp; 053 initialize(initialSize); 054 } 055 056 /** Determines the ordering of objects in this priority queue. 057 * Subclasses can override this method. 058 */ 059 protected boolean lessThan(Object a, Object b) 060 { 061 return myComp.compare(a,b) < 0; 062 } 063 064 public void setComparator(Comparator comp) 065 { 066 myComp = comp; 067 resort(); 068 } 069 070 /** Subclass constructors must call this. */ 071 protected final void initialize(int initialSize) 072 { 073 size = 0; 074 int heapSize = initialSize; 075 heap = new Object[heapSize]; 076 } 077 078 /** Adds an Object to a PriorityQueue in log(size) time. 079 Unless resize occurs ... 080 */ 081 public final void put(Object element) 082 { 083 size++; 084 if ( size >= heap.length ) 085 { 086 Object[] newHeap = new Object[2*heap.length]; 087 for (int i = 1; i < size; i++ ) 088 { 089 newHeap[i] = heap[i]; 090 heap[i] = null; // help GC() ?! 091 } 092 heap = newHeap; 093 } 094 heap[size] = element; 095 upHeap(); 096 } 097 098 /** 099 * Replace the topmost element. 100 */ 101 public final void setTop(Object element) 102 { 103 heap[1] = element; 104 adjustTop(); 105 } 106 107 /** Returns the least element of the PriorityQueue in constant time. */ 108 public final Object top() 109 { 110 if (size > 0) 111 return heap[1]; 112 else 113 return null; 114 } 115 116 /** Removes and returns the least element of the PriorityQueue in log(size) 117 time. */ 118 public final Object pop() 119 { 120 if (size > 0) 121 { 122 Object result = heap[1]; // save first value 123 heap[1] = heap[size]; // move last to first 124 heap[size] = null; // permit GC of objects 125 size--; 126 downHeap(1); // adjust heap 127 return result; 128 } 129 else 130 return null; 131 } 132 133 /** Should be called when the Object at top changes values. Still log(n) 134 * worst case, but it's at least twice as fast to <pre> 135 * { pq.top().change(); pq.adjustTop(); } 136 * </pre> instead of <pre> 137 * { o = pq.pop(); o.change(); pq.push(o); } 138 * </pre> 139 */ 140 public final void adjustTop() 141 { 142 downHeap(1); 143 } 144 145 146 /** Returns the number of elements currently stored in the PriorityQueue. */ 147 public final int getSize() 148 { 149 return size; 150 } 151 152 /** Returns current capacity */ 153 public final int getCapacity() 154 { 155 return heap.length; 156 } 157 158 /** Removes all entries from the PriorityQueue. */ 159 public final void clear() 160 { 161 for (int i = 1; i < size; i++) 162 heap[i] = null; 163 size = 0; 164 } 165 166 /** Rearrange the heap, this is supposed to be 167 O(n*log(n)) but better than nothing 168 */ 169 public void resort() 170 { 171 int i = size / 2; 172 while ( i > 1 ) 173 { 174 downHeap(i); 175 i--; 176 } 177 } 178 179 /** 180 * readjust last node in the heap to maintain heap condition. 181 */ 182 protected final void upHeap() 183 { 184 int i = size; 185 Object node = heap[i]; // save bottom node 186 int j = i >>> 1; 187 while (j > 0 && lessThan(node, heap[j])) 188 { 189 heap[i] = heap[j]; // shift parents down 190 i = j; 191 j = j >>> 1; 192 } 193 heap[i] = node; // install saved node 194 } 195 196 /** 197 * readjust top node in the heap to maintain heap condition. 198 */ 199 protected final void downHeap(int top) 200 { 201 int i = top; 202 Object node = heap[i]; // save top node 203 int j = i << 1; // find smaller child 204 int k = j + 1; 205 if (k <= size && lessThan(heap[k], heap[j])) 206 j = k; 207 while (j <= size && lessThan(heap[j], node)) 208 { 209 heap[i] = heap[j]; // sift up child 210 i = j; 211 j = i << 1; 212 k = j + 1; 213 if (k <= size && lessThan(heap[k], heap[j])) 214 j = k; 215 } 216 heap[i] = node; // place saved node 217 } 218 }