import java.util.ArrayList; /* An instance of this class has a "resident" two-dimensional matrix of ** integer values, provided at construction. In each row of the matrix, ** as well as each column, the values must be in increasing order (with ** no duplicates in any row or column). One can search, with respect ** to a given key, to find all the locations at which it occurs. ** ** Authors: R. McCloskey and < STUDENT's NAME > ** Date: May 2022 */ public class RecSaddleBackSearcher { // instance variables // ------------------ private int probeCntr; // # probes performed since last reset private int[][] matrix; // resident matrix (in which searches occur) private int key; // value most recently searched for // list of locations at which the search key was found during the most // recent call to findAll() private ArrayList locList; // constructor // ----------- /* Establishes the resident matrix of this RecSaddleBackSearcher. ** It is verified that the values in the matrix increase along each ** row and column. If not, an IllegalArgumentException is thrown. */ public RecSaddleBackSearcher(int[][] ary) { if (isValidMatrix(ary)) { matrix = ary; resetProbeCount(); } else { throw new IllegalArgumentException("Unsuitable matrix"); } } // observer // -------- /* Returns (a reference to) the resident matrix. */ public int[][] residentMatrix() { return matrix; } /* Returns the number of probes performed since the last time ** the probe counter was reset. */ public int probeCount() { return probeCntr; } /* Returns the key that was searched for by the most recent call ** to findAll(). */ public int getKey() { return key; } /* Returns the list of locations produced by the most recent call ** to findAll(). */ public ArrayList getLocs() { return locList; } // mutators // -------- /* Resets the probe counter to zero. */ public void resetProbeCount() { probeCntr = 0; } /* Builds an ArrayList (which subsequently can be retrieved via a call to ** getLocs()) containing all the locations in the resident matrix at which ** the given key occurs. */ public void findAll(int key) { this.key = key; locList = new ArrayList(); int numRows = matrix.length; int numCols = matrix[0].length; GridLocation bottom = new GridLocation(0,0); GridLocation top = new GridLocation(numRows-1, numCols-1); findAllAux(bottom, top); } // private methods // --------------- /* Adds to the ArrayList 'locList' (an instance variable) all the ** locations that contain the search key (instance variable 'key') ** within the specified rectangular region of the resident matrix. */ private void findAllAux(GridLocation lowCorner, GridLocation highCorner) { if (isEmptyRegion(lowCorner, highCorner)) { // do nothing, as an empty region contains no occurrences of the key } else { // recursive case, needing to be completed } } /* Reports whether the rectangular region described by the given corner ** locations is empty. */ private boolean isEmptyRegion(GridLocation lowCorner, GridLocation highCorner) { return lowCorner.ROW > highCorner.ROW || lowCorner.COL > highCorner.COL; } /* Returns the lowest-numbered location within a[low..high] containing ** a value that is >= the given key, or high+1 if no such location exists. ** pre: low <= high+1 and values in a[low..high] are in ascending order. */ private int binarySearch(int[] a, int low, int high, int key) { int left = low; int right = high+1; while (left != right) { probeCntr++; int mid = (left + right) / 2; if (a[mid] < key) { left = mid+1; } else { // a[mid] >= key) { right = mid; } } return left; } /* Reports whether or not the given two-dimensional array satisfies ** the conditions required here. One condition is that all rows ** have the same length. The other condition is that the values ** increase along each row and each column. */ private boolean isValidMatrix(int[][] ary) { boolean result; if (!isRectangular(ary)) { result = false; } else { // ary is rectangular; check rows and columns. result = true; int r = 0; while (r != ary.length && result) { // check row r result = isIncreasing(ary[r]); r = r+1; } // Now check columns int numCols = ary[0].length; int c = 0; while (c != numCols && result) { result = isIncreasingColumn(ary, c); c = c+1; } } return result; } /* Reports whether the values in the given array are in ** increasing order. */ private boolean isIncreasing(int[] b) { int i = 1; while (i < b.length && b[i-1] < b[i]) { i = i+1; } return i >= b.length; } /* Reports whether the values in the specified column within ** the given two-dimensional array are in increasing order. ** pre: Every row in b[][] has at least col+1 columns. */ private boolean isIncreasingColumn(int[][] b, int col) { int i = 1; while (i < b.length && b[i-1][col] < b[i][col]) { i = i+1; } return i >= b.length; } /* Reports whether the given two-dimensional array is rectangular ** (meaning that all its rows have the same length). ** pre: b.length != 0 */ private boolean isRectangular(int[][] b) { int numCols = b[0].length; int i = 1; while (i < b.length && b[i].length == numCols) { i = i+1; } return i >= b.length; } }