排序比较器(下)

接着上篇继续写道:

三、在子线程中测试排序
一开始编写代码的时候,排序过程是在主线程中完成的,这样的话,一旦数据量级过大(即出现耗时操作),界面就会出现卡死冻结。为了解决这个问题就使用了Qt的子线程。在子线程中进行排序,也就是使用QObject::moveToThread()这个函数。
对于在子线程中编写代码来说,不太向主线程那样好控制(或者),一般来说,适用于把逻辑简单的,操作耗时的操作放在子线程中。在本程序中,不仅把排序操作,还把写入日志操作放进了子线程。然后主线程和子线程通过信号和槽来进行交流。(主线程释放工作信号给子线程,子线程接受信号开始工作,工作完之后,释放工作完成信号,通知主线程。)

主要代码如下:

//排序工作
void SortWorker::RecSortWorkSig(int i, Sort * sorts)
{

    sorts->InitData();       //拷贝生成测试数据

    //C语言中的函数库,用作微秒级计时
    struct timeval tpstart,tpend;
    double timeuse;
    gettimeofday(&tpstart,NULL);

    switch (i) {
    case SIM_INS_SORT:
        sorts->SimInsSort();     //测试简单插入排序
        break;
    case SHELL_SORT:
        sorts->ShellSort();  //测试希尔插入排序
        break;
    case BUB_SORT:
        sorts->BubSort();        //测试冒泡排序
        break;
    case QUI_SORT:
        sorts->QuiSort(0,sorts->GetDataLength()-1);      //测试快速排序
        break;
    case SIM_SEL_SORT:
        sorts->SimSelSort();     //测试简单排序
        break;
    case HEAP_SORT:
        sorts->HeapSort();       //测试堆排序
        break;
    case MERGE_SORT:
        sorts->MergeSort(0,sorts->GetDataLength()-1);        //测试二路归并排序
        break;
    case COUNT_SORT:
        sorts->CountSort();      //测试计数排序
        break;
    case RAD_SORT:
        sorts->RadSort();        //测试基数排序
        break;
    default:
        break;
    }

    gettimeofday(&tpend,NULL);
    timeuse=(1000000*(tpend.tv_sec-tpstart.tv_sec) + tpend.tv_usec-tpstart.tv_usec)/1000000.0;
    emit SendSortFinishedSig(timeuse);     //释放结束信号,传递用时参数给主线程
}

//写入工作
void SortWorker::RecWriLogWorkSig(Sort *sorts,QTextStream *out)
{
    (*out)<<"\nOriginal data:";

    //写入原始数据
    int length = sorts->GetDataLength();
    for(int i = 0;i<length;++i)
    {
        if(i % 10 == 0)
            (*out)<<"\n"<<sorts->data0[i];
        else
            (*out)<<" "<<sorts->data0[i];
    }
    (*out)<<"\nData after sort:";
    for(int i = 0;i<length;++i)
    {
        if(i % 10 == 0)
            (*out)<<"\n"<<sorts->data[i];
        else
            (*out)<<" "<<sorts->data[i];
    }
    emit SendWriFinishedSig();         //释放写入完成信号
}

这里需要关联主线程和子线程的信号和槽。 Qt的机制保证这里主线程和子线程的的信号和槽可以相互关联。

//关联信号,用于启动排序新线程并从新线程中读取返回的数据
    connect(this,SIGNAL(SendSortWorkSin(int,Sort *)),&sort_worker,SLOT(RecSortWorkSig(int,Sort*)));
 connect(&sort_worker,SIGNAL(SendSortFinishedSig(double)),this,SLOT(RecSortFinishedSig(double)));
    connect(this,SIGNAL(SendWriWorkSig(Sort*,QTextStream *)),&sort_worker,SLOT(RecWriLogWorkSig(Sort*,QTextStream*)));
    connect(&sort_worker,SIGNAL(SendWriFinishedSig()),this,SLOT(RecWriFinishedSig()));

四、等待框的制作
当后台子线程在进行排序和写入日志的过程中,界面不接受用户的输入。此处显示了一个动态的gif等待图片,阻碍主界面。当子线程工作完成之后,释放工作完成信号。主程序接受到信号之后关闭等待框,继续往下执行。如下图所示:等待图片
主要代码如下:

  //显示等待动画
     movie = new QMovie(":/img/wait.gif");
     movie->setScaledSize(QSize(ui->label_wait->width(),ui->label_wait->height()));
     ui->label_wait->setMovie(movie);
     movie->start();

五、测试结果
最终的排序结果将会根据用户的选择是否记录在日志中(比较结果一定会记录,用户可以决定选择是否记录原始数据和排序数据)。注意:日志是的目录是在程序编译的目录,不是源代码的目录。
以下在我电脑上一个数量级为10000的排序结果:

选择的数量规模为:10000
测试比较开始...

简单插入排序开始...
简单插入排序结束。此排序所用时间为:0.166901s
希尔排序开始...
希尔排序结束。此排序所用时间为:0.002999s
冒泡排序开始...
冒泡排序结束。此排序所用时间为:0.48223s
快速排序开始...
快速排序结束。此排序所用时间为:0.002s
简单选择排序开始...
简单选择排序结束。此排序所用时间为:0.192889s
堆排序开始...
堆排序结束。此排序所用时间为:0.003997s
二路归并排序开始...
二路归并排序结束。此排序所用时间为:0.004997s
计数排序开始...
计数排序结束。此排序所用时间为:0.012993s
基数排序开始...
基数排序结束。此排序所用时间为:0.001998s
测试比较结束

本程序最大测试百万级的数据规模,但是对于复杂度为O(N2)的算法来说,十分耗时。比如说冒泡排序,我吃饭之前开始测试,吃完之后,等待框还在继续。但是其他的算法,运行百万级的数据规模还能在可接受的时间内结束。如下图所示:
结果显示
在数据量较小的时候观察不太明显,数据量一旦很大,O(N2)和O(logN)明显就出来了。

完成的工程代码见:点这儿

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值