Java 合并排序是最有效的实现
因此,我想知道Java中合并排序的最有效实现是什么(以防其时间效率会因语言而异)。这个问题可能微不足道,但我的最终目标是向更有经验的程序员学习。下面是我举的两个例子:Java 合并排序是最有效的实现,java,algorithm,sorting,mergesort,Java,Algorithm,Sorting,Mergesort,因此,我想知道Java中合并排序的最有效实现是什么(以防其时间效率会因语言而异)。这个问题可能微不足道,但我的最终目标是向更有经验的程序员学习。下面是我举的两个例子: //version I made. public static double[] mergeSort(double[] arreglo) { if (arreglo.length > 1) { int d = (arreglo.length / 2); double[] arreglo
//version I made.
public static double[] mergeSort(double[] arreglo) {
if (arreglo.length > 1) {
int d = (arreglo.length / 2);
double[] arreglo1 = Arrays.copyOfRange(arreglo, 0, d),
arreglo2 = Arrays.copyOfRange(arreglo, d, arreglo.length);
arreglo1 = mergeSort(arreglo1);
arreglo2 = mergeSort(arreglo2);
return merge(arreglo1, arreglo2);
} else {
return arreglo;
}
}
public static double[] merge(double[] arreglo1, double[] arreglo2) {
double[] convi = new double[arreglo1.length + arreglo2.length];
for (int i = 0, m1 = 0, m2 = 0; i < convi.length; i++) {
if (arreglo1.length > m1 && arreglo2.length > m2) {
if (arreglo1[m1] <= arreglo2[m2])
convi[i] = arreglo1[m1++];
else {
convi[i] = arreglo2[m2++];
}
} else {
convi[i] = (arreglo1.length == m1) ? arreglo2[m2++] : arreglo1[m1++];
}
}
return convi;
}
//Taken out of Cormens book.
public static void mergeSort(int[] arreglo, int i, int f) {
if (f > i) {
int d = ((i + f) / 2);
mergeSort(arreglo, i, d);
mergeSort(arreglo, d + 1, f);
merge(arreglo, i, d, f);
}
}
public static void merge(int[] arreglo, int i, int m, int f) {
int n1 = (m - i) + 1;
int n2 = (f - m);
int[] mitad1 = new int[n1 + 1];
int[] mitad2 = new int[n2 + 1];
for (int v = 0; v < n1; v++) {
mitad1[v] = arreglo[i + v];
}
for (int p = 0; p < n2; p++) {
mitad2[p] = arreglo[p + m + 1];
}
mitad1[n1] = Integer.MAX_VALUE;
mitad2[n2] = Integer.MAX_VALUE;
for (int r = i, m1 = 0, m2 = 0; r <= f; r++) {
if (mitad1[m1] <= mitad2[m2]) {
arreglo[r] = mitad1[m1];
m1++;
} else {
arreglo[r] = mitad2[m2];
m2++;
}
}
}
//我制作的版本。
公共静态双[]合并排序(双[]arreglo){
如果(arreglo.length>1){
int d=(arreglo.length/2);
double[]arreglo1=Arrays.copyOfRange(arreglo,0,d),
arreglo2=Arrays.copyOfRange(arreglo,d,arreglo.length);
arreglo1=合并排序(arreglo1);
arreglo2=合并排序(arreglo2);
返回合并(arreglo1、arreglo2);
}否则{
返回arreglo;
}
}
公共静态双[]合并(双[]arreglo1,双[]arreglo2){
double[]convi=新的双精度[arreglo1.length+arreglo2.length];
for(int i=0,m1=0,m2=0;im1和&arreglo2.length>m2){
if(1[m1]i){
int d=((i+f)/2);
合并排序(arreglo,i,d);
合并排序(arreglo,d+1,f);
合并(arreglo,i,d,f);
}
}
公共静态无效合并(int[]arreglo,int i,int m,int f){
int n1=(m-i)+1;
int n2=(f-m);
int[]minad1=新int[n1+1];
int[]minad2=新的int[n2+1];
对于(int v=0;v 对于(int r= i,M1=0,m2=0;r),下面的程序是从中给出的C++实例转换而来的
它引入了一种改进。它将整个排序数组的一个副本复制到一个辅助数组中,然后进一步处理。接下来,通过在辅助数组和原始数组之间交替,在辅助数组上执行递归拆分,这样就不会发生合并数组的额外复制操作。Basica实际上,该算法在每个递归调用中切换输入和辅助数组的角色。例如,在概念上:
常规合并排序:
--合并
–––––––
该计划:
--合并
--向后合并
( 2 3 5 8 )( 1 4 6 7 )
(( 5 8 )( 2 3 ))(( 1 7 )( 4 6 ))
此外,在将数组分成两半后,如果数组足够小,该算法将使用插入排序
,因为它在小数据集上的性能优于合并排序
。何时准确使用插入排序
的阈值可以通过反复试验确定
守则:
static int M = 10;
//insertion sort to be used once the mergesort partitions become small enough
static void insertionsort(int[] a, int l, int r) {
int i, j, temp;
for (i = 1; i < r + 1; i++) {
temp = a[i];
j = i;
while ((j > 0) && a[j - 1] > temp)
{
a[j] = a[j - 1];
j = j - 1;
}
a[j] = temp;
}
}
//standard merging two sorted half arrays into single sorted array
static void merge(int[] merged_a, int start_a, int[] half_a1, int start_a1, int size_a1,
int[] half_a2, int start_a2, int size_a2) {
int i, j, k;
int total_s = size_a1 + size_a2;
for (i = start_a1, j = start_a2, k = start_a; k < (total_s); k++) {
// if reached end of first half array, run through the loop
// filling in only from the second half array
if (i == size_a1) {
merged_a[k] = half_a2[j++];
continue;
}
// if reached end of second half array, run through the loop
// filling in only from the first half array
if (j == size_a2) {
merged_a[k] = half_a1[i++];
continue;
}
// merged array is filled with the smaller element of the two
// arrays, in order
merged_a[k] = half_a1[i] < half_a2[j] ?
half_a1[i++] : half_a2[j++];
}
}
//merge sort data during merging without the additional copying back to array
//all data movement is done during the course of the merges
static void mergesortNoCopy(int[] a, int[] b, int l, int r) {
if (r - l <= M) {
insertionsort(a + l, l, r - l);
return;
}
int m = (l + r) / 2;
//switch arrays to msort b thus recursively writing results to b
mergesortNoCopy(b, a, l, m); //merge sort left
mergesortNoCopy(b, a, m + 1, r); //merge sort right
//merge partitions of b into a
merge(a, l, b, l, m - l + 1, b, m + 1, r - m); //merge
}
static void mergesort(int[] a) {
int[] aux = Arrays.copyOf(a, a.length);
mergesortNoCopy(a, aux, 0, a.length - 1);
}
static int M=10;
//一旦mergesort分区变得足够小,就要使用插入排序
静态void insertionsort(int[]a,int-l,int-r){
int i,j,温度;
对于(i=1;i0)和&a[j-1]>temp)
{
a[j]=a[j-1];
j=j-1;
}
a[j]=温度;
}
}
//将两个已排序的半数组合并为单个已排序数组的标准方法
静态无效合并(int[]合并,int开始,int[]一半,int开始,int大小,
int[]半个字符,int开始字符,int大小字符){
int i,j,k;
int total_s=尺寸_a1+尺寸_a2;
对于(i=start_a1,j=start_a2,k=start_a;k<(总计);k++){
//如果到达前半个数组的末尾,则运行循环
//仅从下半个数组填充
如果(i==尺寸_a1){
合并的_a[k]=half_a2[j++];
继续;
}
//如果到达数组后半部分的末尾,则运行循环
//仅从前半个数组填充
如果(j==尺寸_a2){
合并的_a[k]=half_a1[i++];
继续;
}
//合并的数组由两个数组中较小的元素填充
//数组,按顺序排列
合并的a[k]=half_a1[i] 如果(r-l第二个更有效,因为它避免了所有的复制步骤。它也简单了一百万倍,更明显,这有它自己的价值,假设它们工作(而且看起来很好),几乎肯定没关系。它们都是O(n log n)
和(通常)在大多数情况下,执行比快速排序更糟糕的操作。一旦你看到情况有多糟糕,你就会想知道为什么你要花这么多时间来完善合并排序。是的,谢谢你的回答。我主要想练习。一个很好的通用技术是为一个被大量使用的库找到源代码,它可以满足你的需要。Java库排序是一个稳定的mergesort对几乎已排序的列表进行了调整。许多聪明人花费了巨大的努力来减少其在许多体系结构上的运行时常数。一定要看一看!谢谢,我得到了在数组和aux之间交替的概念,这样我就不必在每次递归调用中进行复制,但我不明白为什么要添加arrAy类型和INT.这里:合并(A+L,B+L,M+L+1,B+M+ 1,R-M)@ MelviaCu N.AgunThani抱歉,从C++翻译:)在函数Bia[L]中有一个[0 ],对于B是相同的,所以你应该通过起始点,这样,没有复制的合并就好像在CLSR中描述的地方合并一样。
( 2 3 5 8 )( 1 4 6 7 )
(( 5 8 )( 2 3 ))(( 1 7 )( 4 6 ))
static int M = 10;
//insertion sort to be used once the mergesort partitions become small enough
static void insertionsort(int[] a, int l, int r) {
int i, j, temp;
for (i = 1; i < r + 1; i++) {
temp = a[i];
j = i;
while ((j > 0) && a[j - 1] > temp)
{
a[j] = a[j - 1];
j = j - 1;
}
a[j] = temp;
}
}
//standard merging two sorted half arrays into single sorted array
static void merge(int[] merged_a, int start_a, int[] half_a1, int start_a1, int size_a1,
int[] half_a2, int start_a2, int size_a2) {
int i, j, k;
int total_s = size_a1 + size_a2;
for (i = start_a1, j = start_a2, k = start_a; k < (total_s); k++) {
// if reached end of first half array, run through the loop
// filling in only from the second half array
if (i == size_a1) {
merged_a[k] = half_a2[j++];
continue;
}
// if reached end of second half array, run through the loop
// filling in only from the first half array
if (j == size_a2) {
merged_a[k] = half_a1[i++];
continue;
}
// merged array is filled with the smaller element of the two
// arrays, in order
merged_a[k] = half_a1[i] < half_a2[j] ?
half_a1[i++] : half_a2[j++];
}
}
//merge sort data during merging without the additional copying back to array
//all data movement is done during the course of the merges
static void mergesortNoCopy(int[] a, int[] b, int l, int r) {
if (r - l <= M) {
insertionsort(a + l, l, r - l);
return;
}
int m = (l + r) / 2;
//switch arrays to msort b thus recursively writing results to b
mergesortNoCopy(b, a, l, m); //merge sort left
mergesortNoCopy(b, a, m + 1, r); //merge sort right
//merge partitions of b into a
merge(a, l, b, l, m - l + 1, b, m + 1, r - m); //merge
}
static void mergesort(int[] a) {
int[] aux = Arrays.copyOf(a, a.length);
mergesortNoCopy(a, aux, 0, a.length - 1);
}
// after split, before merge
if (a[mid] <= a[mid + 1]) return;