/****************************************************************************** * Compilation: javac BinomialMinPQ.java * Execution: * * A binomial heap. * ******************************************************************************/ package edu.princeton.cs.algs4; import java.util.Iterator; import java.util.Comparator; import java.util.NoSuchElementException; /** * The BinomialMinPQ class represents a priority queue of generic keys. * It supports the usual insert and delete-the-minimum operations, * along with the merging of two heaps together. * 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 binomial heap. * The insert, delete-the-minimum, union, min-key * and size operations take logarithmic time. * The is-empty and constructor operations take constant time. * * @author Tristan Claverie */ public class BinomialMinPQ implements Iterable { private Node head; //head of the list of roots private final Comparator comp; //Comparator over the keys //Represents a Node of a Binomial Tree private class Node { Key key; //Key contained by the Node int order; //The order of the Binomial Tree rooted by this Node Node child, sibling; //child and sibling of this Node } /** * Initializes an empty priority queue * Worst case is O(1) */ public BinomialMinPQ() { comp = new MyComparator(); } /** * Initializes an empty priority queue using the given Comparator * Worst case is O(1) * @param C a comparator over the keys */ public BinomialMinPQ(Comparator C) { comp = C; } /** * Initializes a priority queue with given keys * Worst case is O(n*log(n)) * @param a an array of keys */ public BinomialMinPQ(Key[] a) { comp = new MyComparator(); for (Key k : a) insert(k); } /** * Initializes a priority queue with given keys using the given Comparator * Worst case is O(n*log(n)) * @param C a comparator over the keys * @param a an array of keys */ public BinomialMinPQ(Comparator C, Key[] a) { comp = C; for (Key k : a) insert(k); } /** * 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 head == null; } /** * Number of elements currently on the priority queue * Worst case is O(log(n)) * @throws java.lang.ArithmeticException if there are more than 2^63-1 elements in the queue * @return the number of elements on the priority queue */ public int size() { int result = 0, tmp; for (Node node = head; node != null; node = node.sibling) { if (node.order > 30) { throw new ArithmeticException("The number of elements cannot be evaluated, but the priority queue is still valid."); } tmp = 1 << node.order; result |= tmp; } return result; } /** * Puts a Key in the heap * Worst case is O(log(n)) * @param key a Key */ public void insert(Key key) { Node x = new Node(); x.key = key; x.order = 0; BinomialMinPQ H = new BinomialMinPQ(); //The Comparator oh the H heap is not used H.head = x; this.head = this.union(H).head; } /** * Get the minimum key currently in the queue * Worst case is O(log(n)) * @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"); Node min = head; Node current = head; while (current.sibling != null) { min = (greater(min.key, current.sibling.key)) ? current : min; current = current.sibling; } return min.key; } /** * Deletes the minimum key * Worst case is O(log(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"); Node min = eraseMin(); Node x = (min.child == null) ? min : min.child; if (min.child != null) { min.child = null; Node prevx = null, nextx = x.sibling; while (nextx != null) { x.sibling = prevx; prevx = x; x = nextx;nextx = nextx.sibling; } x.sibling = prevx; BinomialMinPQ H = new BinomialMinPQ(); H.head = x; head = union(H).head; } return min.key; } /** * Merges two Binomial heaps together * This operation is destructive * Worst case is O(log(n)) * @param heap a Binomial Heap to be merged with the current heap * @throws java.lang.IllegalArgumentException if the heap in parameter is null * @return the union of two heaps */ public BinomialMinPQ union(BinomialMinPQ heap) { if (heap == null) throw new IllegalArgumentException("Cannot merge a Binomial Heap with null"); this.head = merge(new Node(), this.head, heap.head).sibling; Node x = this.head; Node prevx = null, nextx = x.sibling; while (nextx != null) { if (x.order < nextx.order || (nextx.sibling != null && nextx.sibling.order == x.order)) { prevx = x; x = nextx; } else if (greater(nextx.key, x.key)) { x.sibling = nextx.sibling; link(nextx, x); } else { if (prevx == null) { this.head = nextx; } else { prevx.sibling = nextx; } link(x, nextx); x = nextx; } nextx = x.sibling; } return this; } /************************************************* * General helper functions ************************************************/ //Compares two keys private boolean greater(Key n, Key m) { if (n == null) return false; if (m == null) return true; return comp.compare(n, m) > 0; } //Assuming root1 holds a greater key than root2, root2 becomes the new root private void link(Node root1, Node root2) { root1.sibling = root2.child; root2.child = root1; root2.order++; } //Deletes and return the node containing the minimum key private Node eraseMin() { Node min = head; Node previous = null; Node current = head; while (current.sibling != null) { if (greater(min.key, current.sibling.key)) { previous = current; min = current.sibling; } current = current.sibling; } previous.sibling = min.sibling; if (min == head) head = min.sibling; return min; } /************************************************** * Functions for inserting a key in the heap *************************************************/ //Merges two root lists into one, there can be up to 2 Binomial Trees of same order private Node merge(Node h, Node x, Node y) { if (x == null && y == null) return h; else if (x == null) h.sibling = merge(y, null, y.sibling); else if (y == null) h.sibling = merge(x, x.sibling, null); else if (x.order < y.order) h.sibling = merge(x, x.sibling, y); else h.sibling = merge(y, x, y.sibling); return h; } /****************************************************************** * 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(log(n)) * hasNext() : Worst case is O(1) * @return an Iterator over the keys in the priority queue in ascending order */ public Iterator iterator() { return new MyIterator(); } private class MyIterator implements Iterator { BinomialMinPQ data; //Constructor clones recursively the elements in the queue //It takes linear time public MyIterator() { data = new BinomialMinPQ(comp); data.head = clone(head, null); } private Node clone(Node x, Node parent) { if (x == null) return null; Node node = new Node(); node.key = x.key; node.sibling = clone(x.sibling, parent); node.child = clone(x.child, node); return node; } 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 { @Override public int compare(Key key1, Key key2) { return ((Comparable) key1).compareTo(key2); } } } /****************************************************************************** * Copyright 2002-2022, 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. ******************************************************************************/