/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: PriorityQueue.java * Written by: Christian Harnisch, Ingo Besenfelder, Michael Neumann (Team 3) * * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.routing.experimentalAStar3.datastructures; /** * Implements a priority queue. * * Taken from: http://www.ntecs.de/projects/yinspire++/src/Algorithms/BinaryHeap.h * * @author: Michael Neumann */ public abstract class PriorityQueue<E> { private int capacity; private int size; private E elements[]; final int MIN_CAPA = 32; public PriorityQueue() { this.capacity = 0; this.size = 0; this.elements = null; } public E[] getElements() { return elements; } public E top() { assert(this.size > 0); return this.elements[1]; } public void pop() { remove(1); } /* * Remove all elements from the PQ. */ public void clear() { for (int i = 1; i <= this.size; ++i) { set_index(this.elements[i], 0); // detach from heap } this.size = 0; } // XXX: this is a hack! public void setEmpty() { this.size = 0; } private void remove(int i) { assert(i <= this.size); // // Element i is removed from the heap and as such becomes // a "bubble" (free element). Move the bubble until // the bubble becomes a leaf element. // set_index(this.elements[i], 0); // detach from heap int bubble = move_bubble_down(i); // // Now take the last element and insert it at the position of // the bubble. In case the bubble is already the last element we // are done. // if (bubble != this.size) { insert_and_bubble_up(bubble, this.elements[this.size]); } --this.size; } public void push(E element) { if (this.size >= this.capacity) resize(2*this.capacity); insert_and_bubble_up(++this.size, element); } public int size() { return this.size; } public boolean empty() { return (this.size == 0); } /* * Insert +element+ into the heap beginning from * +i+ and searching upwards to the root for the * right position (heap ordered) to insert. * * Element at index +i+ MUST be empty, i.e. unused! */ private void insert_and_bubble_up(int i, E element) { for (;i >= 2 && less(element, this.elements[i/2]); i /= 2) { store_element(i, this.elements[i/2]); } // finally store it into the determined hole store_element(i, element); } /* * Move the bubble (empty element) at +i+ down in direction * to the leaves. When the bubble reaches a leaf, stop and * return the index of the leaf element which is now empty. */ private int move_bubble_down(int i) { int sz = this.size; int right_child = i * 2 + 1; while (right_child <= sz) { if (less(this.elements[right_child-1], this.elements[right_child])) { --right_child; // minimum child is left child } store_element(i, this.elements[right_child]); i = right_child; right_child = i * 2 + 1; } // // Edge case (comparison with the last element) // if (right_child-1 == sz) { store_element(i, this.elements[right_child-1]); i = right_child-1; } return i; } private void resize(int new_capacity) { E new_elements[]; if (new_capacity < MIN_CAPA) this.capacity = MIN_CAPA; else this.capacity = new_capacity; new_elements = alloc_array(this.capacity+1); if (this.elements != null) { /* * Copy elements to new array */ for (int i = 1; i <= this.size; ++i) { new_elements[i] = this.elements[i]; } } assert(new_elements != null); assert(this.capacity >= this.size); this.elements = new_elements; } private void store_element(int i, E element) { this.elements[i] = element; set_index(this.elements[i], i); } public void update(E element) { int i = get_index(element); if (i == 0) { push(element); } else { // FIXME: use propagate up/down instead set_index(this.elements[i], 0); // detach from heap int bubble = move_bubble_down(i); insert_and_bubble_up(bubble, element); } } public void remove(E element) { int i = get_index(element); if (i > 0) remove(i); } abstract protected boolean less(E a, E b); abstract protected int get_index(E e); abstract protected void set_index(E e, int new_index); abstract protected E[] alloc_array(int sz); }