]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph/src/com/infomatiq/jsi/PriorityQueue.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / com / infomatiq / jsi / PriorityQueue.java
diff --git a/bundles/org.simantics.scenegraph/src/com/infomatiq/jsi/PriorityQueue.java b/bundles/org.simantics.scenegraph/src/com/infomatiq/jsi/PriorityQueue.java
new file mode 100644 (file)
index 0000000..3b402a8
--- /dev/null
@@ -0,0 +1,254 @@
+//  PriorityQueue.java
+//  Java Spatial Index Library
+//  Copyright (C) 2008 aled@sourceforge.net
+//
+//  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; either
+//  version 2.1 of the License, or (at your option) any later version.
+//  
+//  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.
+//  
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+package com.infomatiq.jsi;
+
+import gnu.trove.TIntArrayList;
+import gnu.trove.TFloatArrayList;
+
+/**
+ * <p>
+ * Priority Queue that stores values as ints and priorities as floats. Uses a
+ * Heap to sort the priorities; the values are sorted "in step" with the
+ * priorities.
+ * </p>
+ * <p>
+ * A Heap is simply an array that is kept semi sorted; in particular if the
+ * elements of the array are arranged in a tree structure; ie
+ * </p>
+ * 
+ *                                   00 
+ *                                 /     \ 
+ *                             01          02 
+ *                            /  \        /  \ 
+ *                          03    04    05    06 
+ *                          /\    /\    /\    /\ 
+ *                        07 08 09 10 11 12 13 14
+ * 
+ * <p>
+ * then each parent is kept sorted with respect to it's immediate children. E.g.
+ * 00 < 01, 00 < 02, 02 < 05, 02 < 06
+ * </p>
+ * <p>
+ * This means that the array appears to be sorted, as long as we only ever look
+ * at element 0.
+ * </p>
+ * <p>
+ * Inserting new elements is much faster than if the entire array was kept
+ * sorted; a new element is appended to the array, and then recursively swapped
+ * with each parent to maintain the "parent is sorted w.r.t it's children"
+ * property.
+ * </p>
+ * <p>
+ * To return the "next" value it is necessary to remove the root element. The
+ * last element in the array is placed in the root of the tree, and is
+ * recursively swapped with one of it's children until the "parent is sorted
+ * w.r.t it's children" property is restored.
+ * </p>
+ * <p>
+ * Random access is slow (eg for deleting a particular value), and is not
+ * implemented here - if this functionality is required, then a heap probably
+ * isn't the right data structure.
+ * </p>
+ * @author Aled Morris <aled@sourceforge.net>
+ * @version 1.0b8
+ */
+public class PriorityQueue {
+  public static final boolean SORT_ORDER_ASCENDING = true;
+  public static final boolean SORT_ORDER_DESCENDING = false;
+
+  private TIntArrayList values = null;
+  private TFloatArrayList priorities = null;
+  private boolean sortOrder = SORT_ORDER_ASCENDING;
+
+  private static boolean INTERNAL_CONSISTENCY_CHECKING = false;
+
+  public PriorityQueue(boolean sortOrder) {
+    this(sortOrder, 10);
+  }
+
+  public PriorityQueue(boolean sortOrder, int initialCapacity) {
+    this.sortOrder = sortOrder;
+    values = new TIntArrayList(initialCapacity);
+    priorities = new TFloatArrayList(initialCapacity);
+  }
+
+  /**
+   * @param p1
+   * @param p2
+   * @return true if p1 has an earlier sort order than p2.
+   */
+  private boolean sortsEarlierThan(float p1, float p2) {
+    if (sortOrder == SORT_ORDER_ASCENDING) {
+      return p1 < p2;
+    }
+    return p2 < p1;
+  }
+
+  // to insert a value, append it to the arrays, then
+  // reheapify by promoting it to the correct place.
+  public void insert(int value, float priority) {
+    values.add(value);
+    priorities.add(priority);
+
+    promote(values.size() - 1, value, priority);
+  }
+
+  private void promote(int index, int value, float priority) {
+    // Consider the index to be a "hole"; i.e. don't swap priorities/values
+    // when moving up the tree, simply copy the parent into the hole and
+    // then consider the parent to be the hole.
+    // Finally, copy the value/priority into the hole.
+    while (index > 0) {
+      int parentIndex = (index - 1) / 2;
+      float parentPriority = priorities.get(parentIndex);
+
+      if (sortsEarlierThan(parentPriority, priority)) {
+        break;
+      }
+
+      // copy the parent entry into the current index.
+      values.set(index, values.get(parentIndex));
+      priorities.set(index, parentPriority);
+      index = parentIndex;
+    }
+
+    values.set(index, value);
+    priorities.set(index, priority);
+
+    if (INTERNAL_CONSISTENCY_CHECKING) {
+      check();
+    }
+  }
+
+  public int size() {
+    return values.size();
+  }
+
+  public void clear() {
+    values.clear();
+    priorities.clear();
+  }
+
+  public void reset() {
+    values.reset();
+    priorities.reset();
+  }
+
+  public int getValue() {
+    return values.get(0);
+  }
+
+  public float getPriority() {
+    return priorities.get(0);
+  }
+
+  private void demote(int index, int value, float priority) {
+    int childIndex = (index * 2) + 1; // left child
+
+    while (childIndex < values.size()) {
+      float childPriority = priorities.get(childIndex);
+
+      if (childIndex + 1 < values.size()) {
+        float rightPriority = priorities.get(childIndex + 1);
+        if (sortsEarlierThan(rightPriority, childPriority)) {
+          childPriority = rightPriority;
+          childIndex++; // right child
+        }
+      }
+
+      if (sortsEarlierThan(childPriority, priority)) {
+        priorities.set(index, childPriority);
+        values.set(index, values.get(childIndex));
+        index = childIndex;
+        childIndex = (index * 2) + 1;
+      } else {
+        break;
+      }
+    }
+
+    values.set(index, value);
+    priorities.set(index, priority);
+  }
+
+  // get the value with the lowest priority
+  // creates a "hole" at the root of the tree.
+  // The algorithm swaps the hole with the appropriate child, until
+  // the last entry will fit correctly into the hole (ie is lower
+  // priority than its children)
+  public int pop() {
+    int ret = values.get(0);
+
+    // record the value/priority of the last entry
+    int lastIndex = values.size() - 1;
+    int tempValue = values.get(lastIndex);
+    float tempPriority = priorities.get(lastIndex);
+
+    values.remove(lastIndex);
+    priorities.remove(lastIndex);
+
+    if (lastIndex > 0) {
+      demote(0, tempValue, tempPriority);
+    }
+
+    if (INTERNAL_CONSISTENCY_CHECKING) {
+      check();
+    }
+
+    return ret;
+  }
+
+  public void setSortOrder(boolean sortOrder) {
+    if (this.sortOrder != sortOrder) {
+      this.sortOrder = sortOrder;
+      // reheapify the arrays
+      for (int i = (values.size() / 2) - 1; i >= 0; i--) {
+        demote(i, values.get(i), priorities.get(i));
+      }
+    }
+    if (INTERNAL_CONSISTENCY_CHECKING) {
+      check();
+    }
+  }
+
+  private void check() {
+    // for each entry, check that the child entries have a lower or equal
+    // priority
+    int lastIndex = values.size() - 1;
+
+    for (int i = 0; i < values.size() / 2; i++) {
+      float currentPriority = priorities.get(i);
+
+      int leftIndex = (i * 2) + 1;
+      if (leftIndex <= lastIndex) {
+        float leftPriority = priorities.get(leftIndex);
+        if (sortsEarlierThan(leftPriority, currentPriority)) {
+          System.err.println("Internal error in PriorityQueue");
+        }
+      }
+
+      int rightIndex = (i * 2) + 2;
+      if (rightIndex <= lastIndex) {
+        float rightPriority = priorities.get(rightIndex);
+        if (sortsEarlierThan(rightPriority, currentPriority)) {
+          System.err.println("Internal error in PriorityQueue");
+        }
+      }
+    }
+  }
+}