MultiwayMinPQ.java 9.13 KB
/******************************************************************************
 *  Compilation: javac MultiwayMinPQ.java   
 *  Execution:
 *  
 *  A multiway heap.
 *  
 ******************************************************************************/

package edu.princeton.cs.algs4;

import java.util.Iterator;
import java.util.Comparator;
import java.util.NoSuchElementException;

/**
 *  The MultiwayMinPQ class represents a priority queue of generic keys.
 *  It supports the usual insert and delete-the-minimum operations.
 *  It also supports methods for peeking at the minimum key,
 *  testing if the priority queue is empty, and iterating through
 *  the keys.
 *  It is possible to build the priority queue using a Comparator.
 *  If not, the natural order relation between the keys will be used.
 *  
 *  This implementation uses a multiway heap.
 *  For simplified notations, logarithm in base d will be referred as log-d
 *  The delete-the-minimum operation takes time proportional to d*log-d(n)
 *  The insert takes time proportional to log-d(n)
 *  The is-empty, min-key and size operations take constant time.
 *  Constructor takes time proportional to the specified capacity.
 *
 *  @author Tristan Claverie
 */
public class MultiwayMinPQ<Key> implements Iterable<Key> {
	private final int d; 				//Dimension of the heap
	private int n;						//Number of keys currently in the heap
	private int order;					//Number of levels of the tree
	private Key[] keys;					//Array of keys
	private final Comparator<Key> comp;	//Comparator over the keys
	
	
    /**
     * Initializes an empty priority queue
     * Worst case is O(d)
     *
     * @param  d dimension of the heap
     * @throws java.lang.IllegalArgumentException if {@code d < 2}
     */
	public MultiwayMinPQ(int d) {
		if (d < 2) throw new IllegalArgumentException("Dimension should be 2 or over");
		this.d = d;
		order = 1;
		keys = (Key[]) new Comparable[d << 1];
		comp = new MyComparator();
	}
	
    /**
     * Initializes an empty priority queue
     * Worst case is O(d)
     *
     * @param  d dimension of the heap
     * @param  comparator a Comparator over the keys
     * @throws java.lang.IllegalArgumentException if {@code d < 2}
     */
	public MultiwayMinPQ(Comparator<Key> comparator, int d) {
		if (d < 2) throw new IllegalArgumentException("Dimension should be 2 or over");
		this.d = d;
		order = 1;
		keys = (Key[]) new Comparable[d << 1];
		comp = comparator;
	}
	
    /**
     * Initializes a priority queue with given indexes
     * Worst case is O(n*log-d(n))
     *
     * @param  d dimension of the heap
     * @param  a an array of keys
     * @throws java.lang.IllegalArgumentException if {@code d < 2}
     */
	public MultiwayMinPQ(Key[] a, int d) {
		if (d < 2) throw new IllegalArgumentException("Dimension should be 2 or over");
		this.d = d;
		order = 1;
		keys = (Key[]) new Comparable[d << 1];
		comp = new MyComparator();
		for (Key key : a) insert(key);
	}
	
    /**
     * Initializes a priority queue with given indexes
     * Worst case is O(a*log-d(n))
     *
     * @param  d dimension of the heap
     * @param  comparator a Comparator over the keys
     * @param  a an array of keys
     * @throws java.lang.IllegalArgumentException if {@code d < 2}
     */
	public MultiwayMinPQ(Comparator<Key> comparator, Key[] a, int d) {
		if (d < 2) throw new IllegalArgumentException("Dimension should be 2 or over");
		this.d = d;
		order = 1;
		keys = (Key[]) new Comparable[d << 1];
		comp = comparator;
		for (Key key : a) insert(key);
	}

        /**
	 * Whether the priority queue is empty
	 * Worst case is O(1)
	 * @return true if the priority queue is empty, false if not
	 */
	public boolean isEmpty() {
		return n == 0;
	}

	/**
	 * Number of elements currently on the priority queue
	 * Worst case is O(1)
	 * @return the number of elements on the priority queue
	 */
	public int size() {
		return n;
	}

	/**
	 * Puts a Key on the priority queue
	 * Worst case is O(log-d(n))
	 * @param key a Key
	 */
	public void insert(Key key) {
		keys[n+d] = key;
		swim(n++);
		if (n == keys.length-d) {
			resize(getN(order+1)+d);
			order++;
		}
	}

	/**
	 * Gets the minimum key currently in the queue
	 * Worst case is O(1)
	 * @throws java.util.NoSuchElementException if the priority queue is empty
	 * @return the minimum key currently in the priority queue
	 */
	public Key minKey() {
		if (isEmpty()) throw new NoSuchElementException("Priority queue is empty");
		return keys[d];
	}

	/**
	 * Deletes the minimum key
	 * Worst case is O(d*log-d(n))
	 * @throws java.util.NoSuchElementException if the priority queue is empty
	 * @return the minimum key
	 */
	public Key delMin() {
		if (isEmpty()) throw new NoSuchElementException("Priority queue is empty");
		exch(0, --n);
		sink(0);
		Key min = keys[n+d];
		keys[n+d] = null;
		int number = getN(order-2);
		if(order > 1 && n == number)  {
			resize(number+(int)Math.pow(d, order-1)+d);
			order--;
		}
		return min;
	}
	
	/***************************
	 * General helper functions
	 **************************/
	
	//Compares two keys
	private boolean greater(int x, int y) {
		int i = x+d, j = y+d;
		if (keys[i] == null) return false;
		if (keys[j] == null) return true;
		return comp.compare(keys[i], keys[j]) > 0;
	}
	
	//Exchanges the position of two keys
	private void exch(int x, int y) {
		int i = x+d, j = y+d;
		Key swap = keys[i];
		keys[i] = keys[j];
		keys[j] = swap;
	}
	
	//Gets the maximum number of keys in the heap, given the number of levels of the tree
	private int getN(int order) {
		return (1-((int)Math.pow(d, order+1)))/(1-d);
	}
	
	/***************************
	 * Functions for moving upward or downward
	 **************************/
	
	//Moves upward
	private void swim(int i) {
		if (i > 0 && greater((i-1)/d, i)) {
			exch(i, (i-1)/d);
			swim((i-1)/d);
		}
	}
	
	//Moves downward
	private void sink(int i) {
		int child = d*i+1;
		if (child >= n) return;
		int min = minChild(i);
		while (min < n && greater(i, min)) {
			exch(i, min);
			i = min;
			min = minChild(i);
		}
	}
	
	/***************************
	 * Deletes the minimum child
	 **************************/
	
	//Return the minimum child of i
	private int minChild(int i) {
		int loBound = d*i+1, hiBound = d*i+d;
		int min = loBound;
		for (int cur = loBound; cur <= hiBound; cur++) {
			if (cur < n && greater(min, cur)) min = cur;
		}
		return min;
	}
	
	/***************************
	 * Resize the priority queue
	 **************************/
	
	//Resizes the array containing the keys
	//If the heap is full, it adds one floor
	//If the heap has two floors empty, it removes one
	private void resize(int N) {
		Key[] array = (Key[]) new Comparable[N];
		for (int i = 0; i < Math.min(keys.length, array.length); i++) {
			array[i] = keys[i];
			keys[i] = null;
		}
		keys = array;
	}
	
	/***************************
	 * Iterator
	 **************************/
	
	/**
	 * Gets an Iterator over the keys in the priority queue in ascending order
	 * The Iterator does not implement the remove() method
	 * iterator() : Worst case is O(n)
	 * next() : 	Worst case is O(d*log-d(n))
	 * hasNext() : 	Worst case is O(1)
	 * @return an Iterator over the keys in the priority queue in ascending order
	 */
	
	public Iterator<Key> iterator() {
		return new MyIterator();
	}
	
	//Constructs an Iterator over the keys in linear time
	private class MyIterator implements Iterator<Key> {
		MultiwayMinPQ<Key> data;
		
		public MyIterator() {
			data = new MultiwayMinPQ<Key>(comp, d);
			data.keys = (Key[]) new Comparable[keys.length];
			data.n = n;
			for (int i = 0; i < keys.length; i++) {
				data.keys[i] = keys[i];
			}
		}

		public boolean hasNext() {
			return !data.isEmpty();
		}
		
		public Key next() {
                        if (!hasNext()) throw new NoSuchElementException();
			return data.delMin();
		}
		
		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
	
	/***************************
	 * Comparator
	 **************************/
	
	//default Comparator
	private class MyComparator implements Comparator<Key> {
		@Override
		public int compare(Key key1, Key key2) {
			return ((Comparable<Key>) key1).compareTo(key2);
		}
	}
	
}

/******************************************************************************
 *  Copyright 2002-2016, Robert Sedgewick and Kevin Wayne.
 *
 *  This file is part of algs4.jar, which accompanies the textbook
 *
 *      Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne,
 *      Addison-Wesley Professional, 2011, ISBN 0-321-57351-X.
 *      http://algs4.cs.princeton.edu
 *
 *
 *  algs4.jar 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.
 *
 *  algs4.jar 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 algs4.jar.  If not, see http://www.gnu.org/licenses.
 ******************************************************************************/