假设我有以下设置:
int[] vectorUsedForSorting = new int[] { 1,0,2,6,3,4,5 }
int[] vectorToBeSorted = new int[] {1,2,3,4,5,6,7}
使用vectorToBeSorted
对vectorUsedForSorting
进行排序的最有效/快捷方法是什么?例如,我希望vectorToBeSorted[0]
成为vectorToBeSorted[1]
,因为vectorUsedForSorting
的第一个元素是1
(即vectorToBeSorted[0]
应该成为`vectorToBeSorted[vectorUsedForSorting[0]]
等等。)
我的目标是在排序算法完成后vectorToBeSorted
为[2,1,3,5,6,7,4]
。
我希望能够非常快速地实现目标。请注意,计算复杂性应该是主要关注点,因为我将对大小为1,000,000或更多的数组进行排序。
如果可能的话,我的目标是亚线性时间复杂度。
答案 0 :(得分:5)
有两种方法可以攻击它。第一个是复制快速排序算法,并使用可以处理你所拥有的间接的东西来更改访问和交换值部分:
int valueAt(int index) { return vectorUsedForSorting[index]; }
int swap(int i1, int i2) {
int tmp = vectorUsedForSorting[i1];
vectorUsedForSorting[i1] = vectorUsedForSorting[i2];
vectorUsedForSorting[i2] = tmp;
tmp = vectorToBeSorted[i1];
vectorToBeSorted[i1] = vectorToBeSorted[i2];
vectorToBeSorted[i2] = tmp;
}
第二种方法是将值复制到新对象中:
public class Item {
int index;
int value;
}
创建一个数组,并使用两个数组中的值创建的Item
填充它们。然后,您可以创建Comparator<Item>
,将其与index
进行比较。
如果有了这个,可以使用Arrays.sort(items, comparator)
对数组进行排序。
如果这还不够快,那么你可以创建N个线程并让每个线程排序原始数组的1 / N.完成后,使用merge sort中的合并步骤加入结果。
答案 1 :(得分:3)
您可以创建一个新数组,对该数组执行排序并将vectorToBeSorted
设置为新数组。
int size = vectorToBeSorted.length;
int[] array = new int[size];
for (int i = 0; i < size; ++i)
array[vectorUsedForSorting[i]] = vectorToBeSorted[i];
vectorToBeSorted = array;
修改强>
如果您希望能够进行排序,则需要循环,交换适当的值。
int size = vectorToBeSorted.length;
for (int i = 0; i < size; ++i) {
int index = vectorUsedForSorting[i];
int value = vectorToBeSorted[index];
vectorUsedForSorting[i] = vectorUsedForSorting[index];
vectorToBeSorted[index] = vectorToBeSorted[i];
vectorUsedForSorting[index] = index;
vectorToBeSorted[i] = value;
}
如果能够创建一个比较索引的结构。你可以用一种;但是,排序肯定比线性解决方案慢。
在这种情况下,这两个陈述是等价的。
array[vectorUsedForSorting[i]] = vectorToBeSorted[i];
array[i] = vectorToBeSorted[vectorUsedForSorting[i]];
答案 2 :(得分:3)
当性能成为一个问题,并且数组很大时,你至少必须考虑一个并行实现(特别是因为这个问题非常平行:它没有太大的努力,应该产生一个很好的,随着核心数量的增加,接近线性加速:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ArrayReordering
{
public static void main(String[] args)
{
basicTest();
performanceTest();
}
private static void basicTest()
{
int[] vectorUsedForSorting = new int[] { 1,0,2,6,3,4,5 };
int[] vectorToBeSorted = new int[] {1,2,3,4,5,6,7};
int[] sortedVectorLinear = new int[vectorToBeSorted.length];
int[] sortedVectorParallel = new int[vectorToBeSorted.length];
sortLinear(vectorUsedForSorting, vectorToBeSorted, sortedVectorLinear);
sortParallel(vectorUsedForSorting, vectorToBeSorted, sortedVectorParallel);
System.out.println("Result Linear "+Arrays.toString(sortedVectorLinear));
System.out.println("Result Parallel "+Arrays.toString(sortedVectorParallel));
}
private static void performanceTest()
{
for (int n=1000000; n<=50000000; n*=2)
{
System.out.println("Run with "+n+" elements");
System.out.println("Creating input data");
int vectorUsedForSorting[] = createVectorUsedForSorting(n);
int vectorToBeSorted[] = new int[n];
for (int i=0; i<n; i++)
{
vectorToBeSorted[i] = i;
}
int[] sortedVectorLinear = new int[vectorToBeSorted.length];
int[] sortedVectorParallel = new int[vectorToBeSorted.length];
long before = 0;
long after = 0;
System.out.println("Running linear");
before = System.nanoTime();
sortLinear(vectorUsedForSorting, vectorToBeSorted, sortedVectorLinear);
after = System.nanoTime();
System.out.println("Duration linear "+(after-before)/1e6+" ms");
System.out.println("Running parallel");
before = System.nanoTime();
sortParallel(vectorUsedForSorting, vectorToBeSorted, sortedVectorParallel);
after = System.nanoTime();
System.out.println("Duration parallel "+(after-before)/1e6+" ms");
//System.out.println("Result Linear "+Arrays.toString(sortedVectorLinear));
//System.out.println("Result Parallel "+Arrays.toString(sortedVectorParallel));
System.out.println("Passed linear? "+
Arrays.equals(vectorUsedForSorting, sortedVectorLinear));
System.out.println("Passed parallel? "+
Arrays.equals(vectorUsedForSorting, sortedVectorParallel));
}
}
private static int[] createVectorUsedForSorting(int n)
{
// Not very elegant, just for a quick test...
List<Integer> indices = new ArrayList<Integer>();
for (int i=0; i<n; i++)
{
indices.add(i);
}
Collections.shuffle(indices);
int vectorUsedForSorting[] = new int[n];
for (int i=0; i<n; i++)
{
vectorUsedForSorting[i] = indices.get(i);
}
return vectorUsedForSorting;
}
private static void sortLinear(
int vectorUsedForSorting[], int vectorToBeSorted[],
int sortedVector[])
{
sortLinear(vectorUsedForSorting, vectorToBeSorted,
sortedVector, 0, vectorToBeSorted.length);
}
static void sortParallel(
final int vectorUsedForSorting[], final int vectorToBeSorted[],
final int sortedVector[])
{
int numProcessors = Runtime.getRuntime().availableProcessors();
int chunkSize = (int)Math.ceil((double)vectorToBeSorted.length / numProcessors);
List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
ExecutorService executor = Executors.newFixedThreadPool(numProcessors);
for (int i=0; i<numProcessors; i++)
{
final int min = i * chunkSize;
final int max = Math.min(vectorToBeSorted.length, min + chunkSize);
Runnable task = new Runnable()
{
@Override
public void run()
{
sortLinear(vectorUsedForSorting, vectorToBeSorted,
sortedVector, min, max);
}
};
tasks.add(Executors.callable(task));
}
try
{
executor.invokeAll(tasks);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
executor.shutdown();
}
private static void sortLinear(
int vectorUsedForSorting[], int vectorToBeSorted[],
int sortedVector[], int min, int max)
{
for (int i = min; i < max; i++)
{
sortedVector[i] = vectorToBeSorted[vectorUsedForSorting[i]];
}
}
}
答案 3 :(得分:2)
怎么样:
int size = size(vectorUsedForSorting);
int [] sortedVector = new int[size];
for (int i = 0; i < size; ++i)
{
sortedVector[i] = vectorToBeSorted[vectorUsedForSorting[i]];
}
还是必须进行排序?