使用多线程进行合并排序

时间:2016-01-31 12:49:23

标签: java multithreading

我尝试使用多线程并行化merge-sort。这是我的代码(请原谅,如果它实现不好。我不关心程序的空间复杂性)。我正在实现排序数组。我的问题是:这个过程是否会减少对大型数组进行排序所需的时间?需要进行哪些修改以使其高效并且是否有用?

import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;

public class Merge {
    public static int[] inputArray;
    public static int[] arr1;
    public static int[] arr2;
    public static int[] arr3;
    public static int t1_status=0;
    public static int t2_status=0;

    public static void main(String[] args) throws IOException{

        System.out.println("Enter the length of the array");

        Scanner in =new Scanner(System.in);

        int arraySize=in.nextInt();

        inputArray = new int[arraySize];

        Random rand=new Random();

        for(int i=0;i<arraySize;i++)
        {
            inputArray[i]=rand.nextInt(100);
        }

        //diving the original array into two subarrays

        arr1=Arrays.copyOfRange(inputArray, 0, inputArray.length/2);

        arr2=Arrays.copyOfRange(inputArray, (inputArray.length)/2,inputArray.length);
        //printing the original array
        System.out.print("The original array is array is ");

        for(int h:inputArray)
        {
            System.out.println(h);
        }

        Thread t1=new Thread(new Runnable(){
                public void run() 
                {
                    mergeSort(arr1);
                    System.out.println("t1 started");
                }

            });
        Thread t2=new Thread(new Runnable(){
                public void run()
                {
                    mergeSort(arr2);
                    System.out.println("t2 started");
                }

            });
        //starting threads
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        }
        catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if(t1.isAlive())
        {
            t1_status=1;
        }
        if(t2.isAlive())
        {
            t2_status=1;
        }
        t1.stop();
        t2.stop();

        arr3=new int[inputArray.length];

        merge(arr3,arr1,arr2);//merging arr1 and arr2.At this point both arr1 and arr2 are sorted.

        System.out.println("The sorted array is ");
        for(int m:arr3)
        {
            System.out.print(m);
            System.out.print(" ");
        }
        System.out.println(" ");
    }

    static void mergeSort(int[] A)
    {
        if (A.length > 1) 
        {
            int q = A.length/2;

            int[] leftArray = Arrays.copyOfRange(A, 0, q);
            int[] rightArray = Arrays.copyOfRange(A,q,A.length);
            mergeSort(leftArray);
            mergeSort(rightArray);
            merge(A,leftArray,rightArray);
        }
    }
    //merge function

    static void merge(int[] a, int[] l, int[] r) {
        int totElem = l.length + r.length;

        int i,li,ri;
        i = li = ri = 0;
        while ( i < totElem) {
            if ((li < l.length) && (ri<r.length)) {
                if (l[li] < r[ri]) {
                    a[i] = l[li];
                    i++;
                    li++;
                }
                else {
                    a[i] = r[ri];
                    i++;
                    ri++;
                }
            }
            else {
                if (li >= l.length) {
                    while (ri < r.length) {
                        a[i] = r[ri];
                        i++;
                        ri++;
                    }
                }
                if (ri >= r.length) {
                    while (li < l.length) {
                        a[i] = l[li];
                        li++;
                        i++;
                    }
                }
            }
        }

        if(t1_status==1){arr1=a;}
        else if(t2_status==1){arr2=a;}
        else{arr3=a;}
    }
}

3 个答案:

答案 0 :(得分:0)

是的,它可以提供帮助,这取决于您拥有多少核心以及您的阵列有多大。产卵线程和协调工作是免费的。关于有多少并行线程实际上有用的地方,情有独钟。

我认为你做的太少了,但这很容易过度:由于这个过程是CPU限制的,你需要每个核心一个线程。

固定的线程池/执行器在这里很方便。

查看CSE373:Data Structures and Algorithms/MergeSort处的一些示例性能增益。

答案 1 :(得分:0)

在单独的线程中对两半进行排序是一个良好的开端,但您也可以通过合并来利用并行性。

另外,你也应该并行处理子索引...但是要跟踪递归的深度,并在你已经使用所有核心时停止创建新的线程。为那些微小的叶子种类制作新线程是一个巨大的开销。

所有在一起:

  1. 拆分为2个帖子
  2. 首先,线程1对源阵列的前半部分进行排序,线程2对源阵列的后半部分进行排序。要对多余的进行排序,它们要么递归调用此函数,要么切换到串行排序,如果2 ^ recursion_depth&gt;核心数;然后
  3. 线程1将两半的前向合并到目标的前半部分,而线程2将两半的后向合并到目标的后半部分。当他们到达目的地的中点时,他们都会停下来。

答案 2 :(得分:0)

请参阅Collections.parallelSort()和Fork / Join框架javadoc。

足够小的数组在单个线程上被归类为遗留物,但是当足够大时(8192,我认为),parallelSort将使用ForkJoinPool默认池(与核心一样多的线程)进行分割和征服。

仅使用2个线程可能会使您的速度加倍,但不会更多。

仅供参考,发射器线程也应该工作,而不仅仅是坐在那里加入。例如,它可以承担第二个线程的工作。然后只加入一次。

相关问题