在选择排序中,降序数组的性能比升序数组更快为什么?

问题描述

我在C visual studio中运行了具有排序数组(升序)和未排序数组(降序)的选择排序算法。 结果是,未排序的数组的性能要比大尺寸的排序数组的性能要快。

我认为这很荒谬。选择排序是否总是需要恒定的时间取决于数组大小? 为什么会这样?

这是selectionsort。我用n = 100,000到1,000,000来运行它。我为每次运行增加了100,000。

int main() {
    int array[1000000]; //1,000
    int i = 100000; //100,000
    int n = 100000; //100,000
    for (int k = 0; k < 10; ++k) {
        insert_ascending(array,n); //stuff elements in ascending order
        //time check
        sort(array,n);

        insert_decending(array,n); //stuff elements in descending order
        //time check
        sort(array,n);

        n += i;
    }
}
void selectionSort(int *list,const int n)
{
    int i,j,indexMin,temp;

    for (i = 0; i < n - 1; i++)
    {
        indexMin = i;
        for (j = i + 1; j < n; j++)
        {
            if (list[j] < list[indexMin])
            {
                indexMin = j;
            }
        }
        temp = list[indexMin];
        list[indexMin] = list[i];
        list[i] = temp;
    } 
}

解决方法

这是我的0.02欧元。

在GCC上未优化的代码中,我可以看到4%的速度差异有利于降序数组而不是升序数组。我的假设是它是由

引起的
if (list[j] < list[indexMin]) {
    indexMin = j;
}

被编译为

        ...
        jge     .L4
        mov     eax,DWORD PTR [rbp-8]
        mov     DWORD PTR [rbp-12],eax
.L4:
        add     DWORD PTR [rbp-8],1

即这不是分支预测失败-对于jge始终为分支的分支,对于下降情况为从不分支。与实际更新缓存中的索引变量相比,jge进入分支确实需要更多的周期。

当然,如果在启用优化的情况下进行编译,则升序代码将获胜。