我将其作为一个问题发布,因为我想与你们澄清在 Java 1.7 中使用 F/J 框架的概念,因为我看到互联网上的一些示例似乎没有意义。
使用列表而不是数组的代码是有意的。
这是递归合并排序的线性/常规版本。
package org.algorithms.sort;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MergeSortor<T> {
private final List<T> items;
private final Comparator<T> c;
public MergeSortor(final List<T> original, final Comparator<T> c) {
if (original == null) {
this.items = Collections.emptyList();
} else {
this.items = original;
}
this.c = c;
}
protected List<T> compute() {
List<T> result = null;
int currentSize = this.items.size();
if (currentSize <= 1) {
result = items;
} else{
int midPoint = currentSize / 2;
List<T> left =new MergeSortor<T>(items.subList(0, midPoint), c).getSortedResult();
List<T> right =new MergeSortor<T>(items.subList(midPoint,
currentSize), c).getSortedResult();
result = merge(left,right);
}
return result;
}
private List<T> merge(List<T>left,List<T>right) {
List<T> result = new ArrayList<T>(left.size()+right.size());
T firstLeft = null;
T firstRight = null;
while (left.size() > 0 || right.size() > 0) {
if (left.size() > 0 && right.size() > 0) {
firstLeft = left.get(0);
firstRight = right.get(0);
if (c.compare(firstLeft, firstRight) <= 0) {
result.add(firstLeft);
left = left.subList(1, left.size());
} else {
result.add(firstRight);
right = right.subList(1, right.size());
}
} else if (left.size() > 0){
result.add(left.get(0));
left = left.subList(1, left.size());
} else if (right.size() > 0){
result.add(right.get(0));
right = right.subList(1, right.size());
}
}
return result;
}
public List<T> getSortedResult() {
return this.compute();
}
static public class IntegerComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
int f = o1.hashCode(); // Auto-unboxing
int s = o2.hashCode(); // Auto-unboxing
return f < s ? -1 : (f == s ? 0 : 1); // No unboxing
}
}
}
这是扩展递归任务的合并排序的 F/J 版本。
package org.algorithms.sort;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.RecursiveTask;
public class MergeTask<T> extends RecursiveTask<List<T>>{
private final List<T> items;
private final Comparator<T> c;
private static final long serialVersionUID = 8193108777395886772L;
public MergeTask(final List<T> original, final Comparator<T> c){
if (original == null) {
this.items = Collections.emptyList();
} else {
this.items = original;
}
this.c = c;
}
@Override
protected List<T> compute() {
List<T> result = null;
int currentSize = this.items.size();
if (currentSize <= 1) {
result = items;
} else{
int midPoint = currentSize / 2;
MergeTask<T> leftSortor = new MergeTask<T>(items.subList(0, midPoint), c);
MergeTask<T> rightSortor = new MergeTask<T>(items.subList(midPoint,
currentSize), c);
rightSortor.fork();
leftSortor.fork();
result = merge(leftSortor.join(),rightSortor.join());
}
return result;
}
private List<T> merge(List<T>left,List<T>right) {
List<T> result = new ArrayList<T>(left.size()+right.size());
T firstLeft = null;
T firstRight = null;
while (left.size() > 0 || right.size() > 0) {
if (left.size() > 0 && right.size() > 0) {
firstLeft = left.get(0);
firstRight = right.get(0);
if (c.compare(firstLeft, firstRight) <= 0) {
result.add(firstLeft);
left = left.subList(1, left.size());
} else {
result.add(firstRight);
right = right.subList(1, right.size());
}
} else if (left.size() > 0){
result.add(left.get(0));
left = left.subList(1, left.size());
} else if (right.size() > 0){
result.add(right.get(0));
right = right.subList(1, right.size());
}
}
return result;
}
}
这是调用它们的主程序。
package org.algorithms.sort;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import org.algorithms.sort.MergeSortor.IntegerComparator;
public class SortingRunner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Integer[] initialOrders = new Integer[Short.MAX_VALUE*32];
Random random = new Random();
for (int i =0 ;i<Short.MAX_VALUE*32;i++){
initialOrders[i]=Integer.valueOf(random.nextInt(Integer.MAX_VALUE));
}
MergeSortor<Integer> sortor = new MergeSortor<Integer>(
Arrays.asList(initialOrders), new IntegerComparator());
ForkJoinPool pool = new ForkJoinPool();
MergeTask<Integer> task = new MergeTask<Integer>(Arrays.asList(initialOrders), new IntegerComparator());
long start = System.currentTimeMillis();
sortor.getSortedResult();
long end = System.currentTimeMillis();
System.out.println(end - start );
start = System.currentTimeMillis();
pool.invoke(task);
end = System.currentTimeMillis();
System.out.println(end - start );
}
}
我在网上考虑的问题是,大多数示例中的分叉是将分割任务的两条腿分叉在一起,或者先分叉左边的分叉部分,然后再分叉右边。
在合并排序中使用 F/J 的情况下,我认为这应该是一个很大的禁忌。
归并排序实际上是从左到右的线性相关排序。先左分叉不会产生任何已经存在的并行进程。F/J 框架将所有你的 fork() 按提交顺序放入队列中,然后由 F/J 池的每个工作线程分别按提交顺序提取和执行。
但是,首先正确分叉将为您提供稍后应该执行的并行计算的优势(与原始/线性实现相比)提前并首先进行尾部的划分/合并。
让我知道你们的想法。并希望这将是使用 F/J 进行排序的一个很好的例子。