自定义排序算法的速度问题

时间:2011-09-22 17:58:33

标签: actionscript-3 algorithm sorting

我正在做一个手动创建排序算法的项目。

经过多次测试后我发现我的heapsort比quicksort更快(我认为应该是另一种方式),我的选择排序也比插入排序快。有谁知道这里的问题是什么?

我正在测试使用从-100到100的整数,随机生成,数组中的5000个值(我修改了这个数字几次,仍然是相同的问题)。 我的快速排序不到位。 我想也许flash的递归函数很慢?我的heapsort使用循环,不像quicksort。这只是一个假设。

这是我的代码,如果他们有帮助的话。我启动一个计时器,运行类的exec()函数,停止计时器并计算经过的时间。代码来自维基百科。 heapsort vs quicksort的问题:

public class Quick {
public static function exec(seq:Vector.<int>):Vector.<int> {
    if (seq.length<=1) {
        return seq;
    }
    var smallPart:Vector.<int>=new Vector.<int>
    var bigPart:Vector.<int>=new Vector.<int>
    var n:int=seq.length;
    var pivotPosition:int=Math.floor(Math.random()*n);
    var pivot:int=seq.splice(pivotPosition,1)[0];
    for (var i:int=0; i<n-1; i++) {
        if (seq[i]<=pivot) {
            smallPart.push(seq[i]);
        } else {
            bigPart.push(seq[i]);
        }
    }
    seq=exec(smallPart).concat(exec(bigPart),Vector.<int>([pivot]));
    return seq;
}

}

public class Heap{
public static function exec(seq:Vector.<int>) {
    var n:int=seq.length;
    heapify(seq);
    var end:int=n-1;
    while (end > 0) {
        var temp:int=seq[end];
        seq[end]=seq[0];
        seq[0]=temp;
        siftDown(seq, 0, end-1);
        end--;
    }
    return seq
}
public static function heapify(seq:Vector.<int>) {
    var n:int=seq.length
    var start:int=n/2-1
    while (start >= 0) {
        siftDown(seq, start, n-1);
        start--;
    }
}
public static function siftDown(seq:Vector.<int>, start:int, end:int) {
    var root:int=start;
    while (root * 2 + 1 <= end) {
        var child:int=root*2+1;
        var swap:int=root;
        if (seq[swap]<seq[child]) {
            swap=child;
        }
        if (child+1<=end&&seq[swap]<seq[child+1]) {
            swap=child+1;
        }
        if (swap!=root) {
            var temp:int=seq[root];
            seq[root]=seq[swap];
            seq[swap]=temp;
            root=swap;
        } else {
            break;
        }    
    }
}

}

插入排序与选择排序的问题:

public class Insertion{
public static function exec(seq:Vector.<int>) {
    var n:int=seq.length;
    for (var i:int=1; i<n; i++) {
        var holder:int=seq[i];
        var j:int=i-1;
        while (seq[j]>holder) {
            seq[j+1]=seq[j];
            j-=1;
            if (j<0) {
                break
            }
        }
        seq[j+1]=holder;
    }
    return seq
}

}

public class Selection{
public static function exec(seq:Vector.<int>):void{
    var currentMinimum:int;
    var n:int=seq.length;
    for (var i:int = 0; i < n-1; i++) {
        currentMinimum=i;
        for (var j:int = i+1; j < n; j++) {
            if (seq[j]<seq[currentMinimum]) {
                currentMinimum=j;
            }
        }
        if (currentMinimum!=i) {
            var temp:int=seq[i];
            seq[i]=seq[currentMinimum];
            seq[currentMinimum]=temp;
        }
    }
}

}

3 个答案:

答案 0 :(得分:3)

好的,所以我实际上并不知道动作脚本,但有很多可能性:

语言问题

我不知道actionscript是如何工作的,但是在C ++和其他可能的语言中,如果你通过值而不是引用传递向量,它可以显着减慢速度。(感谢alxx清除它向上)

在quicksort案例中,您似乎正在创建许多新的向量。如果这个操作很慢(我再次提醒你,我不知道动作脚本)它可能会偏向于支持heapsort。

正如The_asMan所说,也许你的计时方法不准确,也许你应该使用不同的语言功能。

算法问题

您正在使用[-100,100]中的5000个值。这意味着将会有大量的重复。快速排序快速的主要原因之一是您可以使用批次优化。如果存在重复值,则普通(无优化)快速排序可能会非常慢。

此外,还有许多其他优化方法可以使快速排序在实践中更快。

感知问题

嘿。感知问题。 Trololol;)

插入排序不一定比选择排序更快(我不确定从哪里得到这个想法)。插入排序非常快的主要情况是列表几乎已排序。在这种情况下,每个元素的插入只需要几次交换。但是在一般情况下(随机数字)它没有比选择排序有显着优势。

希望这有帮助。

答案 1 :(得分:0)

如果要比较那些排序算法的速度。 那你为什么不预先创建一个随机的Vector / Array。然后测试它的速度。 喜欢:

var source:Vector = new Vector().<5000, true>;
genRandomNumber(source);

var t:int = getTimer();
quicksort(source ....);
t = getTimer() - t;
trace("quicksort:" + t + "ms");

genRandomNumber(source);
t = getTimer();
heapsort(source ...);
t = getTimer() - t;
trace("heapsort:" + t + "ms");
.
.
.

这是kirupa的quicksort演示。我之前测试过一些排序算法,而quicksort是最快的。

答案 2 :(得分:0)

我认为要真正回答这个问题,你需要退后一步,检查你的假设。当你说“heapsort应该比quicksort更快”时,是什么让你这么说?

如果你的理由是“因为有一个更好的大O符号”,你需要回顾一下大O的真正含义。 big O表示法忽略了常数因子,当使用5000这样的小数时,常数因子可以压倒渐近行为。

如果您的理由是“因为维基百科说通常会更快”,那么您需要关注“通常”。许多因素可以影响哪一个更快,例如您的样本量有多大,数字是否已经部分排序,您有多少重复数字。其他因素包括缓存行为 - 某些算法涉及更多本地化的内存访问,并且可以更好地利用缓存。另一方面,与已编译的程序相比,解释性语言可能会或可能不会搞砸那个地方,从而进一步混淆了问题。

你应该尝试的一件事是运行一些不同的测试数据 - 尝试1000万件物品,其中的物品数量从0到40亿左右。然后尝试10个项目,从0到20不等。对于这两种情况,您不一定希望看到相同的算法“获胜”。

您现在使用的测试数据可能不是通用排序算法的最佳用例。如果从仅200个潜在池中选择5000个数字,则可以保证有大量重复数据。如此多的重复数据,计数排序几乎肯定是最快的。

需要考虑的其他事项 - 您对计时功能有多大信心?你知道如果解释或编译动作脚本吗?您是否正在运行测试100次左右,以便进行任何需要完成的初始化工作?