SSPR_25/pokladov_nikita_lab_1/MatrixSorter.java
никита покладов 2c635b4cf1 pokladov_nikita_lab_1 is ready
2025-02-23 21:36:57 +04:00

365 lines
14 KiB
Java

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<Integer>[] 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<Void> 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<Void> leftFuture = sort(indices, rowSums, left, mid);
CompletableFuture<Void> 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<String, RowSumCalculator> sumCalculators = new LinkedHashMap<>();
sumCalculators.put("Single", new SingleThreadRowSumCalculator());
sumCalculators.put("ThreadPool", new ThreadPoolRowSumCalculator(executor));
sumCalculators.put("ForkJoin", new ForkJoinRowSumCalculator());
Map<String, RowSorter> 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<String, RowSumCalculator> sumEntry : sumCalculators.entrySet()) {
for (Map.Entry<String, RowSorter> 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();
}
}