import java.util.Arrays; // for testing purposes only /* This class has a method that computes the ranks of the elements of a given ** array of integers. It uses threads so that the work is done (potentially, ** at least) in parallel. ** ** Author: R. McCloskey ** Date: November 27, 2020 */ public class ArrayRankerParallel { // class constant // -------------- private static final int LENGTH_THRESHOLD = 3; // instance variable // ----------------- private int[] a; // Array whose elements were "ranked" private int[] ranks; // The computed ranks of the elements in a[] // That is, ranks[k] is equal to the number of // elements in a[] that are less than a[k] plus // the number of elements that are both equal to // a[k] and in locations numbered less than k. // Note: The reason for the above being instance variables of this class // is so that (the many) instances of the nested class can access them // without each one needing its own instance variables referring to them. /* Returns the ranks of the elements of the given array. The result is ** computed using a thread based upon an instance of the nested class. */ public int[] ranksOf(int[] ary) { this.a = ary; ranks = new int[ary.length]; RankInParallel ranker = new RankInParallel(0, ary.length); Thread t = new Thread(ranker); t.start(); join(t); return ranks; } /* An instance of this nested class is intended to be used in constructing ** a thread that computes the ranks of the elements in a segment of a[], ** where the boundaries of that segment are provided as parameters to the ** constructor. */ private class RankInParallel implements Runnable { // instance variables // ------------------ int low, high; // Calling computeRanks() on this object results in // ranks[low..high) being filled by the ranks of // a[low..high) wrt a[]. // constructor // ----------- /* Identifies the array segment whose elements are to be ranked by this ** object. ** pre: 0 <= floor <= ceiling <= a.length */ public RankInParallel(int floor, int ceiling) { low = floor; high = ceiling; } // run() method // ------------ public void run() { computeRanks(); } // mutator // ------- /* Computes the ranks of the elements in a[low..high) and places the ** results in ranks[low..high). */ private void computeRanks() { //System.out.printf("Computing ranks of elements in range [%d..%d)\n", // low, high); if (high - low <= LENGTH_THRESHOLD) { // short segment, so rank its rankSeq(); // elements sequentially } else { // split segment into halves and compute the ranks in parallel int mid = (low + high) / 2; RankInParallel leftRIP = new RankInParallel(low, mid); Thread leftThread = new Thread(leftRIP); leftThread.start(); RankInParallel rightRIP = new RankInParallel(mid, high); rightRIP.computeRanks(); // The next three lines are an alternative to the line above; // they create a new thread for the purpose of ranking the elements // in the "right" half of the array segment rather than letting // "this" thread do that job. //Thread rightThread = new Thread(rightRIP); //rightThread.start(); //join(rightThread); join(leftThread); //System.out.printf("Finished ranking elements in range [%d..%d)\n", // low, high); } } /* Computes the ranks of the elements in a[low..high) sequentially, ** placing the results in ranks[low..high) ** pre: 0 <= low <= high <= a.length */ private void rankSeq() { for (int i = low; i != high; i++) { ranks[i] = rankOf(i); } } /* Returns the rank of a[k] wrt a[], which is how many elements in ** a[] are less than a[k], plus how many are equal to it and in ** locations numbered less than k. */ private int rankOf(int k) { final int N = a.length; int count = 0; for (int j=0; j != N; j++) { if (a[j] < a[k] || (j < k && a[j] == a[k])) { count++; } } return count; } } // end of private class /* Applies join() to the given thread, catching InterruptedException ** if it is thrown. */ private void join(Thread t) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(System.out); } } // main() method (for testing purposes) // ------------------------------------ public static void main(String[] args) { int[] ary = new int[] { 3, -7, 15, 2, 5, 18, -9, -1, 4, 12, -17, 2, 19, 31, -7, 8, 0, 4, 16, -11, -2, 9, 6 }; System.out.printf("Array: %s\n", Arrays.toString(ary)); ArrayRankerParallel arp = new ArrayRankerParallel(); System.out.println("Ranking ..."); int[] r = arp.ranksOf(ary); System.out.printf("Ranks are %s\n", Arrays.toString(r)); } }