2 // Java Spatial Index Library
3 // Copyright (C) 2008 aled@sourceforge.net
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 package com.infomatiq.jsi;
21 import gnu.trove.TIntArrayList;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 import gnu.trove.TFloatArrayList;
30 * Priority Queue that stores values as ints and priorities as floats. Uses a
31 * Heap to sort the priorities; the values are sorted "in step" with the
35 * A Heap is simply an array that is kept semi sorted; in particular if the
36 * elements of the array are arranged in a tree structure; ie
45 * 07 08 09 10 11 12 13 14
48 * then each parent is kept sorted with respect to it's immediate children. E.g.
49 * 00 < 01, 00 < 02, 02 < 05, 02 < 06
52 * This means that the array appears to be sorted, as long as we only ever look
56 * Inserting new elements is much faster than if the entire array was kept
57 * sorted; a new element is appended to the array, and then recursively swapped
58 * with each parent to maintain the "parent is sorted w.r.t it's children"
62 * To return the "next" value it is necessary to remove the root element. The
63 * last element in the array is placed in the root of the tree, and is
64 * recursively swapped with one of it's children until the "parent is sorted
65 * w.r.t it's children" property is restored.
68 * Random access is slow (eg for deleting a particular value), and is not
69 * implemented here - if this functionality is required, then a heap probably
70 * isn't the right data structure.
72 * @author Aled Morris <aled@sourceforge.net>
75 public class PriorityQueue {
76 private static final Logger LOGGER = LoggerFactory.getLogger(PriorityQueue.class);
77 public static final boolean SORT_ORDER_ASCENDING = true;
78 public static final boolean SORT_ORDER_DESCENDING = false;
80 private TIntArrayList values = null;
81 private TFloatArrayList priorities = null;
82 private boolean sortOrder = SORT_ORDER_ASCENDING;
84 private static boolean INTERNAL_CONSISTENCY_CHECKING = false;
86 public PriorityQueue(boolean sortOrder) {
90 public PriorityQueue(boolean sortOrder, int initialCapacity) {
91 this.sortOrder = sortOrder;
92 values = new TIntArrayList(initialCapacity);
93 priorities = new TFloatArrayList(initialCapacity);
99 * @return true if p1 has an earlier sort order than p2.
101 private boolean sortsEarlierThan(float p1, float p2) {
102 if (sortOrder == SORT_ORDER_ASCENDING) {
108 // to insert a value, append it to the arrays, then
109 // reheapify by promoting it to the correct place.
110 public void insert(int value, float priority) {
112 priorities.add(priority);
114 promote(values.size() - 1, value, priority);
117 private void promote(int index, int value, float priority) {
118 // Consider the index to be a "hole"; i.e. don't swap priorities/values
119 // when moving up the tree, simply copy the parent into the hole and
120 // then consider the parent to be the hole.
121 // Finally, copy the value/priority into the hole.
123 int parentIndex = (index - 1) / 2;
124 float parentPriority = priorities.get(parentIndex);
126 if (sortsEarlierThan(parentPriority, priority)) {
130 // copy the parent entry into the current index.
131 values.set(index, values.get(parentIndex));
132 priorities.set(index, parentPriority);
136 values.set(index, value);
137 priorities.set(index, priority);
139 if (INTERNAL_CONSISTENCY_CHECKING) {
145 return values.size();
148 public void clear() {
153 public void reset() {
158 public int getValue() {
159 return values.get(0);
162 public float getPriority() {
163 return priorities.get(0);
166 private void demote(int index, int value, float priority) {
167 int childIndex = (index * 2) + 1; // left child
169 while (childIndex < values.size()) {
170 float childPriority = priorities.get(childIndex);
172 if (childIndex + 1 < values.size()) {
173 float rightPriority = priorities.get(childIndex + 1);
174 if (sortsEarlierThan(rightPriority, childPriority)) {
175 childPriority = rightPriority;
176 childIndex++; // right child
180 if (sortsEarlierThan(childPriority, priority)) {
181 priorities.set(index, childPriority);
182 values.set(index, values.get(childIndex));
184 childIndex = (index * 2) + 1;
190 values.set(index, value);
191 priorities.set(index, priority);
194 // get the value with the lowest priority
195 // creates a "hole" at the root of the tree.
196 // The algorithm swaps the hole with the appropriate child, until
197 // the last entry will fit correctly into the hole (ie is lower
198 // priority than its children)
200 int ret = values.get(0);
202 // record the value/priority of the last entry
203 int lastIndex = values.size() - 1;
204 int tempValue = values.get(lastIndex);
205 float tempPriority = priorities.get(lastIndex);
207 values.remove(lastIndex);
208 priorities.remove(lastIndex);
211 demote(0, tempValue, tempPriority);
214 if (INTERNAL_CONSISTENCY_CHECKING) {
221 public void setSortOrder(boolean sortOrder) {
222 if (this.sortOrder != sortOrder) {
223 this.sortOrder = sortOrder;
224 // reheapify the arrays
225 for (int i = (values.size() / 2) - 1; i >= 0; i--) {
226 demote(i, values.get(i), priorities.get(i));
229 if (INTERNAL_CONSISTENCY_CHECKING) {
234 private void check() {
235 // for each entry, check that the child entries have a lower or equal
237 int lastIndex = values.size() - 1;
239 for (int i = 0; i < values.size() / 2; i++) {
240 float currentPriority = priorities.get(i);
242 int leftIndex = (i * 2) + 1;
243 if (leftIndex <= lastIndex) {
244 float leftPriority = priorities.get(leftIndex);
245 if (sortsEarlierThan(leftPriority, currentPriority)) {
246 LOGGER.error("Internal error in PriorityQueue");
250 int rightIndex = (i * 2) + 2;
251 if (rightIndex <= lastIndex) {
252 float rightPriority = priorities.get(rightIndex);
253 if (sortsEarlierThan(rightPriority, currentPriority)) {
254 LOGGER.error("Internal error in PriorityQueue");