我已经编码了2种排序方法(冒泡排序和合并排序),我知道这些排序方法具有不同的效率,因此我想将这些排序方法用于不同的数组大小。只是为了检查时间是否符合预期,我做了一个测试运行,我生成了10000个随机值并将它们放在一个数组中,对它进行了冒泡排序,然后再次生成它们并进行合并排序。我把时间都计算在内。但是,当我查看冒泡排序所花费的时间时,它远远低于合并排序。所以我改变了我先做的那个,现在合并排序最快。为什么会发生这种情况,如何阻止它? 这是我的所有代码。
images
答案 0 :(得分:2)
这可能是JVM变得热身了。尝试运行每个分拣机几次,然后每次运行超过10次并平均时间。
在随机数据的生成中可能是巧合。多次运行将有助于清除它。
答案 1 :(得分:2)
这看起来很奇怪的原因是因为你的BubbleSort实际上并没有对数组进行排序。使用您的代码,给定一个数组[6.0, 5.0, 4.0, 3.0, 2.0, 1.0]
,在运行该方法后,我们结束:[6.0, 5.0, 4.0, 3.0, 2.0, 1.0]
。嗯。这看起来很像我们开始的。
错误很简单。在行
if (ar.get(i).compareTo(ar.get(i + 1)) > 1) {
compareTo
方法返回-1
,0
,1
中的一个,具体取决于参数是否小于,等于或大于。将其更改为
if (ar.get(i).compareTo(ar.get(i + 1)) > 0) {
它会正常工作(而且非常非常缓慢)。
当您的MergeSort正常工作时,您应该会在BubbleSort和MergeSort之间看到截然不同的画面。
答案 2 :(得分:1)
这可能是由于您丢弃第一组100,000个随机生成的Double
对象时所支付的垃圾收集开销。
您可以通过分离测试数据集合并防止它们被垃圾收集来验证此假设,直到两种排序算法都完成为止。
public static void main(String[] args) {
ArrayList<Double> test1 = generateRandomData(100000);
double t1 = System.currentTimeMillis();
mergeSort(test1);
double t2 = System.currentTimeMillis();
ArrayList<Double> test2 = generateRandomData(100000);
double t3 = System.currentTimeMillis();
bubbleSort(test2);
double t4 = System.currentTimeMillis();
System.out.println("Merge sort " + (t2-t1) + " Bubble Sort " + (t4-t3));
}
答案 3 :(得分:1)
另外,使用toReturn.add()可能会影响合并排序。创建一个合并排序条目函数,它执行一次临时数组的分配,然后该函数应该调用实际的合并排序函数并将临时数组作为参数传递,合并排序函数也将临时数组作为参数传递给合并功能。除了entry函数之外,函数不会分配任何数组,只需索引数组以进行比较和移动。
您还可以使用一对相互递归的函数来消除复制到/后退步骤。条目递归函数调用另一个递归函数将sort合并到temp数组中,然后将temp数组中的运行合并到原始数组中。另一个函数将temp数组中的排序合并到原始数组,然后将运行从原始数组合并到temp数组。对于另一个函数,如果运行大小为1,则它将一个元素从原始数组复制到临时数组。对于条目递归函数,如果运行大小为1,那么它只是返回,因为它应该以原始数组中的排序运行结束。
对于大多数语言,自下而上合并排序会稍微快一些,但对于Java来说似乎并没有帮助。同样在merge()中,运行循环的副本应该使用do ....更快,但是使用Java时,使用while会稍快一点,即使总是至少完成一个循环。由于Java泛型是在运行时处理的,因此与在编译时处理的C ++模板相比,它会产生开销(根据参数类型创建多个代码实例)。
从C程序转换的自顶向下合并排序示例(我不熟悉Java)。它不使用泛型类型。我不得不将阵列大小增加到100万,以避免时间显示为0.在我的系统上,Win 7 Pro 64位,Intel 2600K 3.4 ghz,大约需要125 ms(64hz自动收报机因此时间为+/- 15.625 ms)排序100万双打。 1000万双打大约需要1.2秒。
package jsorttd;
import java.util.Random;
public class jsorttd {
static void MergeSort(double a[]) {
if (a.length < 2)
return;
double []b = new double[a.length];
MergeSortAtoA(a, b, 0, a.length);
}
static void MergeSortAtoA(double a[], double 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(double a[], double 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(double []a, double []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
}
}
}
public static void main(String[] args) {
double []a = new double[1000000];
Random r = new Random();
for(int i = 0; i < a.length; i++)
a[i] = r.nextDouble();
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));
}
}