根据RAM模型进行计算,得出使用选择排序可以更有效地排序并且使用mergesort排序效率更低的元素的数量非常低(n <500000)。但是,当我试图测试这个时,我发现选择排序在3分11秒内对500000个元素进行排序,并且合并在6分44秒内完成。我确信这两种算法的实现都是正确的。发生了什么?请解释。
抱歉,我编辑本文的时间已经很晚了。我丢失了网络连接。
所以这是我的mergesort:
public class MergeSort {
// temp array
public static int temp[];
public static void merge(int a[], int low, int mid, int high)
{
temp = new int [a.length];
for(int i = low; i <= high; i++)
temp[i] = a[i];
int i = low;
int j = mid + 1;
int k = low;
while(i <= mid && j <= high)
{
if(temp[i] <= temp[j])
{
a[k] = temp[i];
i++;
}
else
{
a[k] = temp[j];
j++;
}
k++;
}
while(i <= mid)
{
a[k] = temp[i];
k++;
i++;
}
}
public static void sort(int a[], int low, int high)
{
if(low < high)
{
int middle = (low + high) / 2;
// sort the left half
sort(a, low, middle);
// sort the right half
sort(a, middle + 1, high);
// merge parts
merge(a, low, middle, high);
}
}
}
和我的选择排序:
public static int[] selSort(int a[])
{
int length = a.length;
int temp[] = new int [length];
System.arraycopy(a, 0, temp, 0, length);
for(int i = 0; i < length - 1; i++)
{
int smIndex = i;
for(int cIndex = i + 1; cIndex < length; ++cIndex)
if(temp[cIndex] < temp[smIndex])
smIndex = cIndex;
int t = temp[smIndex];
temp[smIndex] = temp[i];
temp[i] = t;
}
return temp;
}
在选择排序中,我正在复制数组。
答案 0 :(得分:1)
问题是merge()基于a.length分配temp [],当它应该只分配temp = new int [high + 1 - low]时。在此修复之后,对temp [i]的引用应更改为temp [i-low]。
使用当前代码,Java必须分配500,000个元素数组,即使它只合并1个偶数和1个奇数元素(高+ 1 - 低== 2)。
稍微优化的自顶向下合并排序的示例,它只分配一次临时缓冲区,然后使用相互递归的函数来避免复制。在此示例中,ee是结束索引== a.length。这将在不到十分之一秒的时间内对500,000个整数进行排序,在不到1.5秒的时间内对10,000,000个整数进行排序。
static void MergeSort(int a[]) {
if (a.length < 2)
return;
int []b = new int[a.length];
MergeSortAtoA(a, b, 0, a.length);
}
static void MergeSortAtoA(int a[], int b[], int ll, int ee)
{
if (ee - ll > 1) {
int rr = (ll + ee)>>1; // midpoint, start of right half
MergeSortAtoB(a, b, ll, rr);
MergeSortAtoB(a, b, rr, ee);
Merge(b, a, ll, rr, ee); // merge b to a
}
}
static void MergeSortAtoB(int a[], int b[], int ll, int ee)
{
if (ee - ll > 1) {
int rr = (ll + ee)>>1; //midpoint, start of right half
MergeSortAtoA(a, b, ll, rr);
MergeSortAtoA(a, b, rr, ee);
Merge(a, b, ll, rr, ee); // merge a to b
} else if ((ee - ll) == 1) {
b[ll] = a[ll];
}
}
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)
while(r < ee){ // else copy rest of right run
b[o++] = a[r++];
}
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)
while(l < rr){ // else copy rest of left run
b[o++] = a[l++];
}
break; // and return
}
}
}