并行归并排序的 Java 实现

并行归并排序 Java 实现

import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;

public class ParallelMergeSort {

    // 主方法,供外部调用
    public static void parallelMergeSort(int[] array) {
        ForkJoinPool pool = new ForkJoinPool();
        pool.invoke(new MergeSortTask(array, 0, array.length - 1));
        pool.shutdown();
    }

    // 合并两个已排序的子数组
    private static void merge(int[] array, int left, int mid, int right) {
        // 创建临时数组存放合并结果
        int[] temp = new int[right - left + 1];
        
        int i = left;    // 左子数组起始索引
        int j = mid + 1;  // 右子数组起始索引
        int k = 0;        // 临时数组索引

        // 合并两个子数组
        while (i <= mid && j <= right) {
            if (array[i] <= array[j]) {
                temp[k++] = array[i++];
            } else {
                temp[k++] = array[j++];
            }
        }

        // 复制左子数组剩余元素
        while (i <= mid) {
            temp[k++] = array[i++];
        }

        // 复制右子数组剩余元素
        while (j <= right) {
            temp[k++] = array[j++];
        }

        // 将临时数组中的元素复制回原数组
        System.arraycopy(temp, 0, array, left, temp.length);
    }

    // 递归任务类
    private static class MergeSortTask extends RecursiveAction {
        private static final int THRESHOLD = 1000; // 阈值,小于此值则使用串行排序
        private final int[] array;
        private final int left;
        private final int right;

        MergeSortTask(int[] array, int left, int right) {
            this.array = array;
            this.left = left;
            this.right = right;
        }

        @Override
        protected void compute() {
            if (right - left <= THRESHOLD) {
                // 小规模数据使用串行排序
                sequentialMergeSort(array, left, right);
            } else {
                int mid = (left + right) >>> 1; // 找到中间点
                
                // 创建子任务
                MergeSortTask leftTask = new MergeSortTask(array, left, mid);
                MergeSortTask rightTask = new MergeSortTask(array, mid + 1, right);
                
                // 并行执行子任务
                invokeAll(leftTask, rightTask);
                
                // 合并结果
                merge(array, left, mid, right);
            }
        }
        
        // 串行归并排序
        private void sequentialMergeSort(int[] array, int left, int right) {
            if (left < right) {
                int mid = (left + right) >>> 1;
                sequentialMergeSort(array, left, mid);
                sequentialMergeSort(array, mid + 1, right);
                merge(array, left, mid, right);
            }
        }
    }

    // 测试代码
    public static void main(String[] args) {
        int size = 10_000_000; // 数组大小
        int[] array = new int[size];
        
        // 生成随机数
        for (int i = 0; i < size; i++) {
            array[i] = (int) (Math.random() * 10_000_000);
        }
        
        System.out.println("开始并行排序...");
        long startTime = System.currentTimeMillis();
        parallelMergeSort(array);
        long endTime = System.currentTimeMillis();
        System.out.println("并行排序耗时: " + (endTime - startTime) + " ms");
        
        // 验证排序结果
        for (int i = 0; i < array.length - 1; i++) {
            if (array[i] > array[i + 1]) {
                System.out.println("排序错误: " + array[i] + " > " + array[i + 1]);
                break;
            }
        }
        System.out.println("排序验证完成");
    }
}

关键点说明

  • 当子问题足够小(小于 THRESHOLD)时,使用串行排序,避免创建过多小任务导致额外开销
  • merge() 方法与串行归并排序相同
  • 需要临时数组存储合并结果
  • 对于小数组,并行版本可能比串行版本慢(由于线程创建和调度的开销)
  • 对于大数组(如百万级别),并行版本通常有明显优势
  • 在实际应用中,可以添加更多性能监控和调优代码

你可能感兴趣的:(数据结构与算法,java,算法,排序算法)