我尝试使用多线程并行化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;}
}
}
答案 0 :(得分:0)
是的,它可以提供帮助,这取决于您拥有多少核心以及您的阵列有多大。产卵线程和协调工作是免费的。关于有多少并行线程实际上有用的地方,情有独钟。
我认为你做的太少了,但这很容易过度:由于这个过程是CPU限制的,你需要每个核心一个线程。
固定的线程池/执行器在这里很方便。
查看CSE373:Data Structures and Algorithms/MergeSort处的一些示例性能增益。
答案 1 :(得分:0)
在单独的线程中对两半进行排序是一个良好的开端,但您也可以通过合并来利用并行性。
另外,你也应该并行处理子索引...但是要跟踪递归的深度,并在你已经使用所有核心时停止创建新的线程。为那些微小的叶子种类制作新线程是一个巨大的开销。
所有在一起:
答案 2 :(得分:0)
请参阅Collections.parallelSort()和Fork / Join框架javadoc。
足够小的数组在单个线程上被归类为遗留物,但是当足够大时(8192,我认为),parallelSort将使用ForkJoinPool默认池(与核心一样多的线程)进行分割和征服。
仅使用2个线程可能会使您的速度加倍,但不会更多。
仅供参考,发射器线程也应该工作,而不仅仅是坐在那里加入。例如,它可以承担第二个线程的工作。然后只加入一次。