C/C++常用排序性能测试(Morn、GSL、qsort、std::sort)

简介

Morn是一个C语言的基础工具和基础算法库,包括数据结构、图像处理、音频处理、机器学习等,具有简单、通用、高效的特点。

GSL(GNU Scientific Library) 是一个用于科学计算的 C 语言类库。

qsort是C语言自带的排序函数,定义在stdlib.h里。

stl(Standard Template Library)C++标准模板库。

性能测试程序源码为:test_sort2.cpp。编译使用以下命令:

g++ -O2 -fopenmp -DNDEBUG test_sort2.cpp -o test_sort2.exe -lgsl -lgslcblas -lmorn

排序性能

这里,把Morn的排序与另外三种排序方法做了对比,它们分别是:①C语言标准库函数里的qsort函数,②科学计算库GSL里的gsl_sort函数,③C++ STL里的std::sort函数。测试程序如下:

#include <algorithm>
#include <gsl/gsl_sort_double.h>
#include "morn_math.h"

int compare(const void *v1, const void *v2) {return ((*((double *)v1))>(*((double *)v2)))?1:-1;}
void test1()
{
    double *data1= (double *)mMalloc(10000000* sizeof(double));
    double *data2= (double *)mMalloc(10000000* sizeof(double));
    double *data3= (double *)mMalloc(10000000* sizeof(double));
    double *data4= (double *)mMalloc(10000000* sizeof(double));
    
    for(int n=1000;n<=10000000;n*=10)
    {
        printf("\n%d data sort for %d times:\n",n,10000000/n);
        for(int i=0;i<10000000;i++)
        {
            data1[i]=((double)mRand(-10000000,10000000))/((double)mRand(1,10000));
            data2[i]=data1[i];data3[i]=data1[i];data4[i]=data1[i];
        }
        
        mTimerBegin("qsort");
        for(int i=0;i<10000000;i+=n) qsort(data1+i,n,sizeof(double),compare);
        mTimerEnd("qsort");
        
        mTimerBegin("gsl");
        for(int i=0;i<10000000;i+=n) gsl_sort(data2+i,1,n);
        mTimerEnd("gsl");
        
        mTimerBegin("stl");
        for(int i=0;i<10000000;i+=n) std::sort(data3+i,data3+i+n);
        mTimerEnd("stl");
        
        mTimerBegin("Morn");
        for(int i=0;i<10000000;i+=n) mAscSort(data4+i,n);
        mTimerEnd("Morn");
    }
    
    mFree(data1); mFree(data2); mFree(data3); mFree(data4);
}

以上对随机生成的双精度浮点:①1000个数据排序,计时10000次;②10000个数据排序,计时1000次;③100000个数据排序,计时100次;④1000000个数据排序,计时10次;⑤10000000个数据排序,计时1次。其运行结果如下:

c0WVPA.png

可以看到:std::sort和Morn的mAscSort速度最快(std::sortmAscSort稍快,差距约2%),在排序数据量小时gsl_sort快于qsort,在数据量大时qsort快于gsl_sort

带索引排序的性能

这里比较的是Morn的mAscSort和GSL的gsl_sort_index函数。测试程序如下:

void test2()
{
    double *data1 = (double *)mMalloc(10000000* sizeof(double));
    double *data2 = (double *)mMalloc(10000000* sizeof(double));
    size_t *index1= (size_t *)mMalloc(10000000* sizeof(size_t));
    int    *index2= (int    *)mMalloc(10000000* sizeof(int   ));

    for(int n=1000;n<=10000000;n*=10)
    {
        printf("\n%d data sort with index for %d times:\n",n,10000000/n);
        for(int i=0;i<10000000;i++)
        {
            data1[i]=((double)mRand(-10000000,10000000))/((double)mRand(1,10000));
            data2[i]=data1[i];
        }
        mTimerBegin("gsl");
        for(int i=0;i<10000000;i+=n) gsl_sort_index(index1,data1+i,1,n);
        mTimerEnd("gsl");
        
        mTimerBegin("Morn");
        for(int i=0;i<10000000;i+=n) mAscSort(data2+i,NULL,index2,n);
        mTimerEnd("Morn");
    }
    
    mFree(data1); mFree(data2);mFree(index1);mFree(index2);
}

以上对随机生成的双精度浮点:①1000个数据排序,计时10000次;②10000个数据排序,计时1000次;③100000个数据排序,计时100次;④1000000个数据排序,计时10次;⑤10000000个数据排序,计时1次。其运行结果如下:

c0fVwF.png

显然:相比GSL,Morn的排序更快。且随着数据量的增加,差距拉大。
这里gsl_sort_indexmAscSort函数功能有区别。gsl_sort_index只输出排序后的索引,对数据不会排序,mAscSort对数据和索引都会排序。

最大最小值子集的性能

首先比较Morn的mMinSubset函数和stl的std::nth_element函数。测试程序如下:

void test3_1()
{
    double *data1= (double *)mMalloc(10000000*sizeof(double));
    double *data2= (double *)mMalloc(10000000*sizeof(double));
    for(int n=100000;n<=10000000;n*=10)
        for(int m=n/10;m<n;m+=n/5)
        {
            printf("\nselect %d from %d data for %d times\n",m,n,10000000/n);
            for(int i=0;i<10000000;i++)
            {
                data1[i]=((double)mRand(-1000000,1000000))/((double)mRand(1,1000));
                data2[i]=data1[i];
            }
            mTimerBegin("stl");
            for(int i=0;i<10000000;i+=n) std::nth_element(data1+i,data1+i+m-1,data1+i+n);
            mTimerEnd("stl");
            
            mTimerBegin("Morn");
            for(int i=0;i<10000000;i+=n) mMinSubset(data2+i,n,m);
            mTimerEnd("Morn");
        }
    mFree(data1);mFree(data2);
}

以上对随机生成的双精度浮点:①从100000数据中分别择出10000、30000、50000、70000、90000个最小子集,计时100次;②从1000000数据中分别择出100000、300000、500000、700000、900000个最小子集,计时10次;③从10000000数据中分别择出1000000、3000000、5000000、7000000、9000000个最小子集,计时1次;

测试结果如下:

c0htBT.png

可见,mMinSubsetstd::nth_element性能基本处于同一水平

这里mMinSubsetstd::nth_element函数功能有细微差别,在解决top n问题时,两者输出的最小子集都是无序的,但是std::nth_element会将临界值写入数组的位置n,而mMinSubset不会将临界值写入位置n,而是以返回值的形式输出。

其次比较Morn的mMinSubset函数和GSL库的gsl_sort_smallest函数。测试程序如下:

void test3_2()
{
    int n=1000000;int m;
    double *in  = (double *)mMalloc(n * sizeof(double));
    double *out1= (double *)mMalloc(n * sizeof(double));
    double *out2= (double *)mMalloc(n * sizeof(double));
    for (int i=0;i<n;i++) in[i] = ((double)mRand(-10000,10000))/10000.0;
    
    for(m=100000;m<n;m+=200000)
    {
        printf("\nselect %d from %d data\n",m,n);
        mTimerBegin("gsl" ); gsl_sort_smallest(out1,m,in,1,n); mTimerEnd("gsl" );
        mTimerBegin("Morn"); mMinSubset(in,n,out2,m);          mTimerEnd("Morn");
    }

    mFree(in); mFree(out1); mFree(out2);
}

这里,从1000000个随机生成的double数据中,分别取出100000、300000、500000、700000、900000个数据,

c07YuR.png

可以看到,两者的耗时差距巨大。
不过这里需要说明的是:gsl_sort_smallestmMinSubset函数的功能不完全相同,它们虽然都是从m个数据中取出最小的n个,但是gsl_sort_smallest取出的数据是按照顺序排列好的,其取值的阈值就是out1[n]mMinSubset取出的数据是无序的,其取值的阈值是函数的返回值。(gsl_sort_smallest的功能更类似std::partial_sort)。

带索引的最大最小值子集的性能

这里比较了Morn的mMaxSubset函数和GSL的gsl_sort_largest_index函数,测试程序如下:

void test4()
{
    int n=1000000;int m;
    double *in  = (double *)mMalloc(n * sizeof(double));
    size_t *out1= (size_t *)mMalloc(n * sizeof(size_t));
    int    *out2= (int    *)mMalloc(n * sizeof(int   ));
    for (int i=0;i<n;i++) in[i] = ((double)mRand(-10000,10000))/10000.0;
    
    for(m=100000;m<n;m+=200000)
    {
        printf("\nselect %d from %d data with index\n",m,n);
        mTimerBegin("gsl" ); gsl_sort_largest_index(out1,m,in,1,n); mTimerEnd("gsl" );
        mTimerBegin("Morn"); mMaxSubset(in,n,NULL,out2,m);          mTimerEnd("Morn");
    }

    mFree(in); mFree(out1); mFree(out2);
}

这里,从1000000个随机生成的double数据中,分别取出100000、300000、500000、700000、900000个数据,测试结果如下:

c07Gv9.png

显然Morn的排序快的多。
这里gsl_sort_largest_indexmMaxSubset也是有区别的。gsl_sort_largest_index只输出排序后的索引,且索引对应的数据是有序的。mAscSort会输出索引和数据,且数据是无序的。

总结:

项目Mornstd::sortGSLqsort
速度较慢
数据类型任意数值类型,其他类型使用mListSort任意类型double任意类型(使用void*)
索引无(但可借助回调函数实现)无(但可借助回调函数实现)
支持回调mListSort支持支持不支持支持
降序排序支持借助回调函数不支持借助回调函数
最大最小子集支持支持支持不支持
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值