/* An instance of this class represents a complete binary tree. ** Let T be a binary tree of height h. Then T is a "complete" binary tree ** if, for k = 0, 1, 2, ..., h-1, there are 2^k nodes of depth k, which is ** to say that every "level" of the tree, except possibly the lowest (which ** include the nodes at depth h), has the maximum possible number of nodes ** in it. In addition, the nodes on the lowest level (level h) need to be ** "as far to the left as possible". ** The nodes are identified by the natural numbers in the range [0..n), ** where n is the number of nodes in the tree. The root is node #0; the ** "rightmost" node on the lowest level is node #n-1. ** ** Author: R. McCloskey ** Date: April 2024 */ public class CompleteBinTree { // class constant // -------------- private static int DEFAULT_INIT_LENGTH = 8; // instance variables // ------------------- private T[] node; // values in the nodes private int numNodes; // # nodes in the tree // constructor // ----------- /* Establishes this complete binary tree to be empty. */ public CompleteBinTree() { node = (T[])(new Object[DEFAULT_INIT_LENGTH]); numNodes = 0; } // observers // --------- /* Returns the # of nodes in this tree. */ public int sizeOf() { return numNodes; } /* Returns true if this tree is empty (meaning it has no nodes), ** otherwise false. */ public boolean isEmpty() { return numNodes == 0; } /* Returns the element in node #k. */ public T elemAt(int k) { return node[k]; } /* Returns the ID of node k's parent. */ public int idOfParent(int k) { return (k-1) / 2; } /* Returns the ID of node k's left child (or what would be that ** node's ID if it existed). */ public int idOfLeftChild(int k) { return 2*k + 1; } /* Returns the ID Of node k's right child (or what would be that ** node's ID if it existed). */ public int idOfRightChild(int k) { return idOfLeftChild(k) + 1; } /* Reports whether or not node k has a left child. */ public boolean hasLeftChild(int k) { return idOfLeftChild(k) >= numNodes; } /* Reports whether or not node k has a right child. */ public boolean hasRightChild(int k) { return idOfRightChild(k) >= numNodes; } /* Reports whether or not node k is a leaf node. */ public boolean isLeaf(int k) { return !hasLeftChild(k); } // mutators // -------- /* Places the specified value into the specified node (i.e., node k), ** replacing whatever value had been there. ** pre: 0 <= k < sizeOf() */ public void replaceElem(int k, T val) { node[k] = val; } /* Inserts a new node containing the specified value. */ public void insertNode(T val) { // In case the node[] array is full, double its length. if (numNodes == node.length) { resizeArray(2 * numNodes); } numNodes++; node[numNodes] = val; } /* Has the effect of making the node[] array have the specified length. */ private void resizeArray(int m) { // Create a new array of the specified length and copy the meaningful // elements of node[] into it. T[] newNodes = (T[])(new Object[m]); for (int i=0; i != numNodes; i++) { newNodes[i] = node[i]; } // Make the 'node' variable refer to the new array, thereby seemingly // changing its length. node = newNodes; } /* Removes the highest-numbered node and returns the value that was there. ** pre: !isEmpty() */ public T removeNode() { numNodes--; T result = elemAt(numNodes); // or: node[numNodes] return result; } }