import java.util.*; import java.util.concurrent.*; public class MatrixSorter { public static char[][] generateMatrix(int rows, int cols) { char[][] matrix = new char[rows][cols]; Random random = new Random(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { matrix[i][j] = (char) random.nextInt(100); } } return matrix; } public static char[][] copyMatrix(char[][] matrix) { char[][] copy = new char[matrix.length][matrix[0].length]; for (int i = 0; i < matrix.length; i++) { System.arraycopy(matrix[i], 0, copy[i], 0, matrix[i].length); } return copy; } public static void printMatrix(char[][] matrix) { for (char[] row : matrix) { for (char value : row) { System.out.print((int) value + " "); } System.out.println(); } } public interface RowSumCalculator { int[] calculateRowSums(char[][] matrix) throws Exception; } public interface RowSorter { Integer[] sortIndices(int[] rowSums) throws Exception; } public static class SingleThreadRowSumCalculator implements RowSumCalculator { @Override public int[] calculateRowSums(char[][] matrix) { int rows = matrix.length; int[] sums = new int[rows]; for (int i = 0; i < rows; i++) { int sum = 0; for (char value : matrix[i]) { sum += value; } sums[i] = sum; } return sums; } } public static class ThreadPoolRowSumCalculator implements RowSumCalculator { private ExecutorService executor; public ThreadPoolRowSumCalculator(ExecutorService executor) { this.executor = executor; } @Override public int[] calculateRowSums(char[][] matrix) throws Exception { int rows = matrix.length; int[] sums = new int[rows]; @SuppressWarnings("unchecked") Future[] futures = new Future[rows]; for (int i = 0; i < rows; i++) { final int row = i; futures[i] = executor.submit(() -> { int sum = 0; for (char value : matrix[row]) { sum += value; } return sum; }); } for (int i = 0; i < rows; i++) { sums[i] = futures[i].get(); } return sums; } } public static class ForkJoinRowSumCalculator implements RowSumCalculator { private static final int THRESHOLD = 100; private ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors()); @Override public int[] calculateRowSums(char[][] matrix) { int rows = matrix.length; int[] sums = new int[rows]; pool.invoke(new RowSumTask(matrix, 0, rows, sums)); return sums; } private static class RowSumTask extends RecursiveAction { private char[][] matrix; private int start, end; private int[] sums; public RowSumTask(char[][] matrix, int start, int end, int[] sums) { this.matrix = matrix; this.start = start; this.end = end; this.sums = sums; } @Override protected void compute() { if (end - start <= THRESHOLD) { for (int i = start; i < end; i++) { int sum = 0; for (char value : matrix[i]) { sum += value; } sums[i] = sum; } } else { int mid = (start + end) / 2; RowSumTask leftTask = new RowSumTask(matrix, start, mid, sums); RowSumTask rightTask = new RowSumTask(matrix, mid, end, sums); invokeAll(leftTask, rightTask); } } } } public static class SingleThreadRowSorter implements RowSorter { @Override public Integer[] sortIndices(int[] rowSums) { int n = rowSums.length; Integer[] indices = new Integer[n]; for (int i = 0; i < n; i++) { indices[i] = i; } mergeSort(indices, rowSums, 0, n - 1); return indices; } private void mergeSort(Integer[] indices, int[] rowSums, int left, int right) { if (left < right) { int mid = left + (right - left) / 2; mergeSort(indices, rowSums, left, mid); mergeSort(indices, rowSums, mid + 1, right); merge(indices, rowSums, left, mid, right); } } private void merge(Integer[] indices, int[] rowSums, int left, int mid, int right) { int leftSize = mid - left + 1; int rightSize = right - mid; Integer[] leftArr = new Integer[leftSize]; Integer[] rightArr = new Integer[rightSize]; System.arraycopy(indices, left, leftArr, 0, leftSize); System.arraycopy(indices, mid + 1, rightArr, 0, rightSize); int i = 0, j = 0, k = left; while (i < leftSize && j < rightSize) { if (rowSums[leftArr[i]] >= rowSums[rightArr[j]]) { indices[k++] = leftArr[i++]; } else { indices[k++] = rightArr[j++]; } } while (i < leftSize) { indices[k++] = leftArr[i++]; } while (j < rightSize) { indices[k++] = rightArr[j++]; } } } public static class ForkJoinRowSorter implements RowSorter { private static final int THRESHOLD = 100; private ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors()); @Override public Integer[] sortIndices(int[] rowSums) { int n = rowSums.length; Integer[] indices = new Integer[n]; for (int i = 0; i < n; i++) { indices[i] = i; } pool.invoke(new MergeSortTask(indices, rowSums, 0, n - 1)); return indices; } private static class MergeSortTask extends RecursiveAction { private Integer[] indices; private int[] rowSums; private int left, right; public MergeSortTask(Integer[] indices, int[] rowSums, int left, int right) { this.indices = indices; this.rowSums = rowSums; this.left = left; this.right = right; } @Override protected void compute() { if (right - left <= THRESHOLD) { Arrays.sort(indices, left, right + 1, Comparator.comparingInt((Integer i) -> rowSums[i]).reversed()); } else { int mid = left + (right - left) / 2; MergeSortTask leftTask = new MergeSortTask(indices, rowSums, left, mid); MergeSortTask rightTask = new MergeSortTask(indices, rowSums, mid + 1, right); invokeAll(leftTask, rightTask); merge(indices, rowSums, left, mid, right); } } private void merge(Integer[] indices, int[] rowSums, int left, int mid, int right) { Integer[] temp = new Integer[right - left + 1]; int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (rowSums[indices[i]] >= rowSums[indices[j]]) { temp[k++] = indices[i++]; } else { temp[k++] = indices[j++]; } } while (i <= mid) { temp[k++] = indices[i++]; } while (j <= right) { temp[k++] = indices[j++]; } System.arraycopy(temp, 0, indices, left, temp.length); } } } public static class ThreadPoolRowSorter implements RowSorter { private ExecutorService executor; private int THRESHOLD; public ThreadPoolRowSorter(ExecutorService executor, int threshold) { this.executor = executor; this.THRESHOLD = threshold; } @Override public Integer[] sortIndices(int[] rowSums) throws Exception { int n = rowSums.length; Integer[] indices = new Integer[n]; for (int i = 0; i < n; i++) { indices[i] = i; } sort(indices, rowSums, 0, n - 1).get(); return indices; } private CompletableFuture sort(Integer[] indices, int[] rowSums, int left, int right) { if (right - left <= THRESHOLD) { Arrays.sort(indices, left, right + 1, Comparator.comparingInt((Integer i) -> rowSums[i]).reversed()); return CompletableFuture.completedFuture(null); } else { int mid = left + (right - left) / 2; CompletableFuture leftFuture = sort(indices, rowSums, left, mid); CompletableFuture rightFuture = sort(indices, rowSums, mid + 1, right); return CompletableFuture.allOf(leftFuture, rightFuture) .thenRunAsync(() -> merge(indices, rowSums, left, mid, right), executor); } } private void merge(Integer[] indices, int[] rowSums, int left, int mid, int right) { Integer[] temp = new Integer[right - left + 1]; int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (rowSums[indices[i]] >= rowSums[indices[j]]) { temp[k++] = indices[i++]; } else { temp[k++] = indices[j++]; } } while (i <= mid) { temp[k++] = indices[i++]; } while (j <= right) { temp[k++] = indices[j++]; } System.arraycopy(temp, 0, indices, left, temp.length); } } public static class CombinedMatrixSorter { private RowSumCalculator sumCalculator; private RowSorter rowSorter; public CombinedMatrixSorter(RowSumCalculator sumCalculator, RowSorter rowSorter) { this.sumCalculator = sumCalculator; this.rowSorter = rowSorter; } public long sort(char[][] matrix) throws Exception { long startTime = System.currentTimeMillis(); int[] rowSums = sumCalculator.calculateRowSums(matrix); Integer[] sortedIndices = rowSorter.sortIndices(rowSums); long endTime = System.currentTimeMillis(); char[][] sortedMatrix = reorderMatrix(matrix, sortedIndices); return endTime - startTime; } private char[][] reorderMatrix(char[][] matrix, Integer[] indices) { char[][] sortedMatrix = new char[matrix.length][]; for (int i = 0; i < indices.length; i++) { sortedMatrix[i] = matrix[indices[i]]; } return sortedMatrix; } } public static void main(String[] args) throws Exception { int[] rowCounts = {10, 100, 1000, 10000, 100000, 1000000}; int[] colCounts = {1000000, 100000, 10000, 1000, 100, 10}; ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); Map sumCalculators = new LinkedHashMap<>(); sumCalculators.put("Single", new SingleThreadRowSumCalculator()); sumCalculators.put("ThreadPool", new ThreadPoolRowSumCalculator(executor)); sumCalculators.put("ForkJoin", new ForkJoinRowSumCalculator()); Map rowSorters = new LinkedHashMap<>(); rowSorters.put("Single", new SingleThreadRowSorter()); rowSorters.put("ThreadPool", new ThreadPoolRowSorter(executor, 100)); rowSorters.put("ForkJoin", new ForkJoinRowSorter()); int trials = 10; for (int sizeIndex = 0; sizeIndex < rowCounts.length; sizeIndex++) { int rows = rowCounts[sizeIndex]; int cols = colCounts[sizeIndex]; System.out.printf("Matrix size: %d x %d%n", rows, cols); for (Map.Entry sumEntry : sumCalculators.entrySet()) { for (Map.Entry sortEntry : rowSorters.entrySet()) { long totalTime = 0; for (int t = 0; t < trials; t++) { char[][] matrix = generateMatrix(rows, cols); CombinedMatrixSorter sorter = new CombinedMatrixSorter(sumEntry.getValue(), sortEntry.getValue()); long time = sorter.sort(matrix); totalTime += time; } System.out.printf("Summation: %-10s | Sorting: %-10s -> Average Time: %d ms%n", sumEntry.getKey(), sortEntry.getKey(), totalTime / trials); } } System.out.println(); } executor.shutdown(); } }