// BinaryHeap class // // CONSTRUCTION: with optional capacity (that defaults to 100) // or an array containing initial items // // ******************PUBLIC OPERATIONS********************* // void insert( x ) --> Insert x // Comparable deleteMin( )--> Return and remove smallest item // Comparable findMin( ) --> Return smallest item // boolean isEmpty( ) --> Return true if empty; else false // void makeEmpty( ) --> Remove all items // void delete( x ) --> Deletes x from the Binary Heap // ******************ERRORS************************************** // Throws UnderflowException as appropriate /** * Implements a binary heap. * Note that all "matching" is based on the compareTo method. * @author Mark Allen Weiss * EDITED */ public class BinaryHeap> { /** * Construct the binary heap. */ public BinaryHeap( ) { this( DEFAULT_CAPACITY ); } /** * Construct the binary heap. * @param capacity the capacity of the binary heap. */ public BinaryHeap( int capacity ) { currentSize = 0; array = (AnyType[]) new Comparable[ capacity + 1 ]; // initializes a new hash table to store locations of values locationsTable = new SeparateChainingHashTable(array.length); } /** * Construct the binary heap given an array of items. */ public BinaryHeap( AnyType [ ] items ) { currentSize = items.length; array = (AnyType[]) new Comparable[ ( currentSize + 2 ) * 11 / 10 ]; // initializes a new hash table to store locations of values locationsTable = new SeparateChainingHashTable(array.length); int i = 1; for( AnyType item : items ){ array[ i++ ] = item; locationsTable.insert(new Foo(item,i-1)); // sets each new item into the hash table // with its associated array location } buildHeap( ); } /** * Insert into the priority queue, maintaining heap order. * Update the hashtable each time an element is entered into * the array. The hashtable is a map of the heap array. * Duplicates are not allowed. * @param x the item to insert. */ public void insert( AnyType x ) { if(!isPresent(x)){ // makes the heap NOT allow for duplicates so the hash table will work if( currentSize == array.length - 1 ) enlargeArray( array.length * 2 + 1 ); // Percolate up int hole = ++currentSize; for( ; hole > 1 && x.compareTo( array[ hole / 2 ] ) < 0; hole /= 2 ){ array[ hole ] = array[ hole / 2 ]; locationsTable.remove(new Foo(array[hole])); locationsTable.insert(new Foo(array[hole],hole)); // updates location by reinserting into hash table } array[ hole ] = x; locationsTable.insert(new Foo(array[hole],hole)); // updates the location in the hashtable } } private void enlargeArray( int newSize ) { AnyType [] old = array; array = (AnyType []) new Comparable[ newSize ]; for( int i = 0; i < old.length; i++ ) array[ i ] = old[ i ]; } /** * Find the smallest item in the priority queue. * @return the smallest item, or throw an UnderflowException if empty. */ public AnyType findMin( ) { if( isEmpty( ) ){ //throw new UnderflowException( ); return null; } return array[ 1 ]; } /** * Remove the smallest item from the priority queue. * Update the hashtable after removing an element. * Delete that element from the hashtable. * @return the smallest item, or throw an UnderflowException if empty. */ public AnyType deleteMin( ) { if( isEmpty( ) ){ //throw new UnderflowException( ); return null; } AnyType minItem = findMin(); if(minItem == null){ // if item not in heap, do nothing return null; } locationsTable.remove(new Foo(array[1])); // removes the element we're deleting from the hash table array[ 1 ] = array[ currentSize-- ]; locationsTable.remove(new Foo(array[1])); // removes the element we moved into the root // position from the hash table so we can // update its position during percolation percolateDown( 1 ); return minItem; } /** * Establish heap order property from an arbitrary * arrangement of items. Runs in linear time. */ private void buildHeap( ) { for( int i = currentSize / 2; i > 0; i-- ) percolateDown( i ); } /** * Test if the priority queue is logically empty. * @return true if empty, false otherwise. */ public boolean isEmpty( ) { return currentSize == 0; } /** * Make the priority queue logically empty. */ public void makeEmpty( ) { currentSize = 0; } private static final int DEFAULT_CAPACITY = 10; private int currentSize; // Number of elements in heap private AnyType [ ] array; // The heap array private SeparateChainingHashTable locationsTable; // hash table for storing elements and // their locations using HashEl objects /** * Internal method to percolate down in the heap. * @param hole the index at which the percolate begins. */ private void percolateDown( int hole ) { if(currentSize>0){ int child; AnyType tmp = array[ hole ]; for( ; hole * 2 <= currentSize; hole = child ) { child = hole * 2; if( child != currentSize && array[ child + 1 ].compareTo( array[ child ] ) < 0 ) child++; if( array[ child ].compareTo( tmp ) < 0 ){ locationsTable.remove(new Foo(array[hole])); // removes the element we're array[ hole ] = array[ child ]; // deleting from the hash table locationsTable.remove(new Foo(array[child])); locationsTable.insert(new Foo(array[hole],hole)); // updates the location of }else // the element being percolated up break; // by re-adding it to the hash table } array[ hole ] = tmp; locationsTable.insert(new Foo(array[hole],hole)); } } // public delete method that deletes the input x from the Binary Heap if it is // present somewhere in the heap public boolean delete(AnyType x){ if(this.isEmpty()){ //returns false if no elements in the heap return false; }else if(currentSize == 1){ // if there is only one element in the heap if(array[1].equals(x)){ deleteMin(); // uses deleteMin() to remove the only element if it is return true; // equal to the element we're looking for }else{ return false; } }else if(isPresent(x)){ // if the size of the heap is > 1 and the element is in the heap if(array[1].equals(x)){ deleteMin(); // deletes the first element if that element is the one we're return true; // looking for }else{ int location = getLocation(x); // location of the element in the heap array int hole = location; // placeholder that holds the location while percolating // percolates the element we were looking for up to the root position for( ; hole > 1 ; hole /= 2 ){ AnyType temp = array[hole]; //saves the element previously in this location array[ hole ] = array[ hole / 2 ]; locationsTable.remove(new Foo(array[hole])); locationsTable.insert(new Foo(array[hole],hole)); //updates location of element array[hole/2] = temp; // finishes the swap as the element is percolated up locationsTable.remove(new Foo(array[hole/2])); locationsTable.insert(new Foo(array[hole/2],hole/2)); // updates location of element } deleteMin(); // deletes the element now that it is in the root position // even though it is not really the 'min' buildHeap(); //re-sorts elements of heap to ensure the Heap Ordering Property return true; } } return false; } // retrieves location of given element x in the current BinaryHeap using newly-created method // in the SeparateChainingHashTable class public int getLocation(AnyType x){ return locationsTable.getHeapLocation(new Foo(x)); } // returns boolean value that indicates whether the given object x // is in the current BinaryHeap public boolean isPresent(AnyType x){ return locationsTable.contains(new Foo(x)); } // Test program public static void main( String [ ] args ) { int numItems = 10000; BinaryHeap h = new BinaryHeap( ); /*int i = 37; for( i = 37; i != 0; i = ( i + 37 ) % numItems ) h.insert( i ); for( i = 1; i < numItems; i++ ) if( h.deleteMin( ) != i ) System.out.println( "Oops! " + i );*/ // inserts and deletes several elements over and over again h.insert(13); h.insert(21); h.insert(16); h.insert(24); h.insert(31); h.insert(19); h.insert(68); h.insert(65); h.insert(26); h.insert(32); // prints out the resulting locations of inserted numbers to ensure the delete // method is working properly (a location value of 0 indicates not present) System.out.println(h.getLocation(13)); System.out.println(h.getLocation(24)); System.out.println(h.getLocation(31)); System.out.println(h.getLocation(68)); System.out.println(h.getLocation(26)); } }