Java迭代合并排序运行时
我目前正在为学校做一个项目,要求我为不同的排序算法编写代码。最困难的部分是在给定长度为2^N的输入数组的情况下编写merge sort的迭代版本。我使用了一个名为merge的必需助手方法来帮助迭代合并 我的结构如下。给定一个2^N的数组(让我们使用16的数组大小来解释我的方法),我遍历数组,查看每个2个整数,如果一个大于另一个,则使用merge()进行交换。此过程将在长度为16的数组中发生8次。然后,我将遍历数组,查看每4个整数,4次。我将使用我的合并方法来合并每组4中的两个有序对。然后,我会看一个由8个整数组成的块…以此类推。我的代码发布在这里:Java迭代合并排序运行时,java,arrays,sorting,merge,mergesort,Java,Arrays,Sorting,Merge,Mergesort,我目前正在为学校做一个项目,要求我为不同的排序算法编写代码。最困难的部分是在给定长度为2^N的输入数组的情况下编写merge sort的迭代版本。我使用了一个名为merge的必需助手方法来帮助迭代合并 我的结构如下。给定一个2^N的数组(让我们使用16的数组大小来解释我的方法),我遍历数组,查看每个2个整数,如果一个大于另一个,则使用merge()进行交换。此过程将在长度为16的数组中发生8次。然后,我将遍历数组,查看每4个整数,4次。我将使用我的合并方法来合并每组4中的两个有序对。然后,我会看
public static void MergeSortNonRec(long[] a) {
//======================
//FILL IN YOUR CODE HERE
//======================
/*
System.out.print("Our array is: ");
printArray(a);
System.out.println('\n');
*/
int alength = a.length;
int counter = 2;
//the counter will iterate through levels 2n - 2 4 8 16 32 etc.
int pointtracker = 0;
//the point tracker will keep track of the position in the array
while (counter <= alength) {
long [] aux = new long [alength];
int low = pointtracker;
int high = pointtracker + counter - 1;
int mid = (low + high)/2;
merge(a, aux, low, mid, high);
if (high < alength - 1) {
pointtracker += counter;
//move to the next block
}
else {
//if our high point is at the end of the array
counter *= 2;
pointtracker = 0;
//start over at a[0], with a doubled counter
}
}
/*
System.out.print("Final array is: ");
printArray(a);
System.out.println('\n');
*/
}//MergeSortNonRec()
publicstaticvoidmergesortnonrec(长[]a){
//======================
//在这里填写您的代码
//======================
/*
System.out.print(“我们的数组是:”);
打印阵列(a);
System.out.println('\n');
*/
int alength=a.长度;
int计数器=2;
//计数器将遍历级别2n-2 4 8 16 32等。
int pointtracker=0;
//点跟踪器将跟踪阵列中的位置
while(柜台)
我可以做些什么来减少迭代合并排序的时间
Wiki有一个迭代(自底向上)合并排序的简化示例:
为了减少时间,只需一次性分配aux[]数组,不要在每次合并过程中复制数据,而是在每次合并过程中交换对数组的引用
long [] t = a; // swap references
a = aux;
aux = t;
如果数组的大小是2的奇数次幂,则需要将数组复制一次或就地交换,而不是执行第一次合并过程
迭代合并排序应该比递归合并排序运行得更快
假设这两个函数的版本都经过合理优化,迭代合并排序通常会更快,但相对差异会随着数组大小的增加而减小,因为大部分时间将花费在merge()函数中,该函数对于迭代合并排序和递归合并排序都是相同的
这是一个折衷方案。递归版本将把length-2或2*length-2对索引推送到堆栈或从堆栈中弹出,而迭代则会动态生成索引(可以保存在寄存器中)。在更深层次的递归过程中,递归版本似乎对缓存更友好,因为它在数组的一部分上运行,而迭代版本在每次传递时总是在整个数组上运行,但我从未见过这样的情况,即递归合并排序能带来更好的整体性能。MoPC上的st缓存是4路或更多路集关联的,因此两行用于输入,一行用于合并过程中的输出。在我的测试中,多线程迭代合并排序比单线程迭代合并排序快得多,因此我测试的系统上的合并排序没有内存带宽限制
下面是一个经过优化的迭代(自底向上)合并排序示例以及一个测试程序:
package jsortbu;
import java.util.Random;
public class jsortbu {
static void MergeSort(int[] a) // entry function
{
if(a.length < 2) // if size < 2 return
return;
int[] b = new int[a.length];
BottomUpMergeSort(a, b);
}
static void BottomUpMergeSort(int[] a, int[] b)
{
int n = a.length;
int s = 1; // run size
if(1 == (GetPassCount(n)&1)){ // if odd number of passes
for(s = 1; s < n; s += 2) // swap in place for 1st pass
if(a[s] < a[s-1]){
int t = a[s];
a[s] = a[s-1];
a[s-1] = t;
}
s = 2;
}
while(s < n){ // while not done
int ee = 0; // reset end index
while(ee < n){ // merge pairs of runs
int ll = ee; // ll = start of left run
int rr = ll+s; // rr = start of right run
if(rr >= n){ // if only left run
do // copy it
b[ll] = a[ll];
while(++ll < n);
break; // end of pass
}
ee = rr+s; // ee = end of right run
if(ee > n)
ee = n;
Merge(a, b, ll, rr, ee);
}
{ // swap references
int[] t = a;
a = b;
b = t;
}
s <<= 1; // double the run size
}
}
static void Merge(int[] a, int[] b, int ll, int rr, int ee) {
int o = ll; // b[] index
int l = ll; // a[] left index
int r = rr; // a[] right index
while(true){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
do // else copy rest of right run
b[o++] = a[r++];
while(r < ee);
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
do // else copy rest of left run
b[o++] = a[l++];
while(l < rr);
break; // and return
}
}
}
static int GetPassCount(int n) // return # passes
{
int i = 0;
for(int s = 1; s < n; s <<= 1)
i += 1;
return(i);
}
public static void main(String[] args) {
int[] a = new int[10000000];
Random r = new Random();
for(int i = 0; i < a.length; i++)
a[i] = r.nextInt();
long bgn, end;
bgn = System.currentTimeMillis();
MergeSort(a);
end = System.currentTimeMillis();
for(int i = 1; i < a.length; i++){
if(a[i-1] > a[i]){
System.out.println("failed");
break;
}
}
System.out.println("milliseconds " + (end-bgn));
}
}
jsortbu包;
导入java.util.Random;
公共类jsortbu{
静态void MergeSort(int[]a)//输入函数
{
if(a.length<2)//if size<2返回
返回;
int[]b=新的int[a.长度];
BottomUpMergeSort(a,b);
}
静态void BottomUpMergeSort(int[]a,int[]b)
{
int n=a.长度;
int s=1;//运行大小
if(1==(GetPassCount(n)&1)){//if奇数个过程
对于(s=1;s=n){//如果只剩下左运行
复制它吗
b[ll]=a[ll];
而(++lln)
ee=n;
合并(a、b、ll、rr、ee);
}
{//交换引用
int[]t=a;
a=b;
b=t;
}
s我能够解决我的问题-只是必须将long[]aux移到while循环之外,因为它基本上是一个空数组,只是被merge()改变了方法,但不需要在每次传递时都实例化。@TVK-我用一个稍微优化的合并排序版本更新了我的答案。在我的系统(英特尔3770K 3.5ghz,Win 7 Pro 64位,NetBeans 8.1)上对1000万个整数进行排序大约需要1.1秒。
long [] t = a; // swap references
a = aux;
aux = t;
package jsortbu;
import java.util.Random;
public class jsortbu {
static void MergeSort(int[] a) // entry function
{
if(a.length < 2) // if size < 2 return
return;
int[] b = new int[a.length];
BottomUpMergeSort(a, b);
}
static void BottomUpMergeSort(int[] a, int[] b)
{
int n = a.length;
int s = 1; // run size
if(1 == (GetPassCount(n)&1)){ // if odd number of passes
for(s = 1; s < n; s += 2) // swap in place for 1st pass
if(a[s] < a[s-1]){
int t = a[s];
a[s] = a[s-1];
a[s-1] = t;
}
s = 2;
}
while(s < n){ // while not done
int ee = 0; // reset end index
while(ee < n){ // merge pairs of runs
int ll = ee; // ll = start of left run
int rr = ll+s; // rr = start of right run
if(rr >= n){ // if only left run
do // copy it
b[ll] = a[ll];
while(++ll < n);
break; // end of pass
}
ee = rr+s; // ee = end of right run
if(ee > n)
ee = n;
Merge(a, b, ll, rr, ee);
}
{ // swap references
int[] t = a;
a = b;
b = t;
}
s <<= 1; // double the run size
}
}
static void Merge(int[] a, int[] b, int ll, int rr, int ee) {
int o = ll; // b[] index
int l = ll; // a[] left index
int r = rr; // a[] right index
while(true){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
do // else copy rest of right run
b[o++] = a[r++];
while(r < ee);
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
do // else copy rest of left run
b[o++] = a[l++];
while(l < rr);
break; // and return
}
}
}
static int GetPassCount(int n) // return # passes
{
int i = 0;
for(int s = 1; s < n; s <<= 1)
i += 1;
return(i);
}
public static void main(String[] args) {
int[] a = new int[10000000];
Random r = new Random();
for(int i = 0; i < a.length; i++)
a[i] = r.nextInt();
long bgn, end;
bgn = System.currentTimeMillis();
MergeSort(a);
end = System.currentTimeMillis();
for(int i = 1; i < a.length; i++){
if(a[i-1] > a[i]){
System.out.println("failed");
break;
}
}
System.out.println("milliseconds " + (end-bgn));
}
}