import java.util.Arrays; /* An instance of this class represents a max-heap of integer values. ** In a max-heap, the value at each node is less-than-or-equal-to ** the value in its parent. ** ** Authors: R. McCloskey and < STUDENT(s)' NAMES > ** Date: May 2022 ** Known Defects: ... */ public class MaxHeapOfInt { // class constant // -------------- private static int INIT_CAP_DEFAULT = 8; // instance variables // ------------------ private int numNodes; // # of elements currently occupying this heap private int[] nodes; // nodes[0..numNodes) contains the values in this heap // constructors // ------------ /* Establishes this as being an empty heap, with the underlying ** array representation having the default capacity. */ public MaxHeapOfInt() { this(INIT_CAP_DEFAULT); } /* Establishes this as being an empty heap, with the underlying ** array representation having the indicated capacity. */ public MaxHeapOfInt(int initCapacity) { numNodes = 0; nodes = new int[initCapacity]; } /* Establishes this as being a max-heap containing the values ** in the given array. */ public MaxHeapOfInt(int[] vals) { numNodes = vals.length; // Copy the elements from the given array into instance variable nodes[] nodes = Arrays.copyOf(vals, numNodes); // Now heapify the complete binary tree represented by the array // by rearranging its elements so that the max-heap property is // satisfied. heapify(0); } // observers // --------- /* Reports whether or not this max-heap is empty (i.e., has no elements). */ public boolean isEmpty() { return numNodes == 0; } /* Returns the number of elements in this max-heap. */ public int sizeOf() { return numNodes; } /* Returns the largest value in this max-heap, which is the value ** in its root. ** pre: !isEmpty() */ public int getMax() { return -999; } // STUB!! /* Reports whether or not the contents of nodes[0..numNodes) is ** consistent with it representing a max-heap, which requires that, ** for each k in [1..numNodes), nodes[k] <= nodes[locOfParent(k)]. ** If the parameter is true, a message is printed for each instance ** of that condition failing to be satisfied. */ public boolean isValid(boolean loud) { boolean goodSoFar = true; for (int i = 1; i < numNodes && (loud || goodSoFar); i++) { int iParent = locOfParent(i); if (nodes[i] > nodes[iParent]) { goodSoFar = false; if (loud) { System.out.printf("** ERROR: Node @%d (%d) has larger value than node @%d (%d)\n", i, nodes[i], iParent, nodes[iParent]); } } } return goodSoFar; } /* Displays this heap. */ public void print() { if (numNodes == 0) { System.out.println("Heap is empty."); } else { printAux(0,0); } } /* Auxiliary method for displaying the heap. ** The first parameter indicates the ID of the node at the ** root of the subtree to be displayed. The second parameter ** indicates the indentation level. */ private void printAux(int k, int indentLevel) { if (k < numNodes) { printSpaces(3 * indentLevel); System.out.printf("%d:%d\n", k, nodes[k]); printAux(locOfLeftChild(k), indentLevel + 1); printAux(locOfRightChild(k), indentLevel + 1); } } /* Prints a sequence of spaces of the specified length. */ private void printSpaces(int length) { // Doesn't work. Why not?? //String format = "%" + length + 's'; //System.out.printf(format, ""); // Print the spaces, one per loop iteration. for (int i=0; i != length; i++) { System.out.print(' '); } } // mutators // -------- /* Inserts into this max-heap the specified value. */ public void insert(int val) { // Double the length of nodes[] if it is full. if (numNodes == nodes.length) { nodes = Arrays.copyOf(nodes, 2*numNodes); } nodes[numNodes] = val; siftUp(numNodes); numNodes++; } /* Removes from this max-heap its maximum value, and also returns ** that value. ** pre: !isEmpty() */ public int deleteMax() { int result = getMax(); numNodes = numNodes - 1; nodes[0] = nodes[numNodes]; siftDown(0); return result; } // private methods // --------------- /* Reports whether node k is an interior node. (The other possibilities ** are that node k is a leaf or that there is no node k in this heap.) ** pre: 0 <= k */ private boolean isInterior(int k) { return k <= (numNodes - 2) / 2; } /* The next three methods return the locations, within the array, ** of node k's parent, left child, and right child, respectively. */ private int locOfParent(int k) { return (k-1) / 2; } private int locOfLeftChild(int k) { return 2*k + 1; } private int locOfRightChild(int k) { return 2*k + 2; } /* Reports whether or not node k has a left child. */ private boolean hasLeftChild(int k) { return locOfLeftChild(k) < numNodes; } /* Reports whether or not node k has a right child. */ private boolean hasRightChild(int k) { return locOfRightChild(k) < numNodes; } /* Rearranges the values in the subtree rooted at node k so that ** that subtree forms a max-heap. (If no node k exists, nothing ** happens.) */ private void heapify(int k) { if (isInterior(k)) { heapify(locOfLeftChild(k)); heapify(locOfRightChild(k)); siftDown(k); } } /* Sifts up from node k. ** Which is to say that, if the value in node k is greater than that in its ** parent, the two values are swapped and we continue sifting upward from ** the parent node. The process ends when either node k is the root or its ** value is not greater than its parent's value. */ private void siftUp(int k) { // STUB } /* Sifts down from node k. ** Which is to say that, if the value in node k is not at least as large as ** that in its larger-valued child, those values are swapped and we continue ** sifting downward from that child. The process ends when either node k ** is not an interior node or node k's value is greater than that in all ** its children. Care must be taken to account for the possibility that ** node k has only a left child. */ private void siftDown(int k) { STUB! } /* Swaps the values at the specified locations of nodes[]. */ private void swap(int i, int j) { int temp = nodes[i]; nodes[i] = nodes[j]; nodes[j] = temp; } }