Qt5-可视化九大经典排序算法(九)桶排序

本章依旧建立开始两篇文章的基础上(冒泡排序插入排序的传送门)。介绍一下,本程序可视化条件已经在冒泡排序中实现完成,避免重复,就只需将剩下的排序算法函数实现下就可以了,另外在插入排序重新实现了随机生成数组数据rand函数(可生成不带重复的数据的放入数组中,让动图显得更好看点)

先引用一下Wiki的介绍:

桶排序(Bucket sort)或所谓的箱排序,是一个排序演算法,工作的原理是将阵列分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序演算法或是以递回方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间({\displaystyle \Theta (n)}{\displaystyle \Theta (n)}大O符号))。但桶排序并不是比较排序,他不受到{\displaystyle O(n\log n)}{\displaystyle O(n\log n)}下限的影响。

桶排序以下列程序进行:

  1. 设置一个定量的阵列当作空桶子。
  2. 寻访序列,并且把项目一个一个放到对应的桶子去。
  3. 对每个不是空的桶子进行排序。
  4. 从不是空的桶子里把项目再放回原来的序列中。

代码实现:

void Bubble::goBucket()
{
    int max = data[0];
    for(int i = 1 ;i < length; i ++){
        if(data[i] > max)
            max = data[i];
    }
    max ++;                         //加一是为了防止数组越界
    QVector<int> b[10];             //假设放十个桶,这个可以自定义
    for (int i = 0; i < length; i++) {
        int bi = 10*data[i]/max;    //前一个桶的每个数据必然小于后一个桶的每个数据
        b[bi].push_back(data[i]);   //然后将数据以一定间隔放置数据
    }

    int c = 0,len =0;   //c用来表示新放入数组的位子,len表示经历各个桶的累长度
    for(int i = 0; i < 10; i ++){
        //这里本想使用sort库来实现各个桶内的排序方便偷个懒的
        //可是那样就不好动图表现了,就用了直接插入排序来代替了,好像也不是很好看
        //std::sort(b[i].begin(),b[i].end());
        for(int j = 1; j < b[i].size(); j++){
            //直接插入排序
            int k;
            if(b[i][j] < b[i][j - 1]){
                int temp = b[i][j];
                for (k = j - 1;k>= 0&&temp < b[i][k];k--) {
                    b[i][k+1] = b[i][k];
                    bubbleSignal(k + len);
                    QThread::msleep(static_cast<unsigned int>(mDelay));
                }
                b[i][k + 1] = temp;
//                bubbleSignal(k + len);
//                QThread::msleep(static_cast<unsigned int>(mDelay));
            }
        }
        len += b[i].size();
        for(int j = 0; j < b[i].size(); j++){
            data[c++] = b[i].at(j);
            bubbleSignal(c);
            QThread::msleep(static_cast<unsigned int>(mDelay));
        }
    }
    for(int i = 0; i < length;i++){
        bubbleSignal(i);
        QThread::msleep(static_cast<unsigned int>(mDelay));
    }
}

运行结果(其实这动图应该是有点误导性的,这是因为data的数据我是等每个桶排序完成再重新赋值回的):

针对动图表现的改良,先是代码改良(在这里我将桶内的数据提前重赋值回了data中,然后在data中以每个桶所对应的长度为间隔直接进行插入排序):

void Bubble::goBucket()
{
    int max = data[0];
    for(int i = 1 ;i < length; i ++){
        if(data[i] > max)
            max = data[i];
    }
    max ++;                         //加一是为了防止数组越界
    QVector<int> b[10];             //假设放十个桶,这个可以自定义
    for (int i = 0; i < length; i++) {
        int bi = 10*data[i]/max;
        b[bi].push_back(data[i]);   //然后将数据以10为间隔放置数据
    }

    int c = 0,len =0;   //c用来表示新放入数组的位子,len表示经历各个桶的累长度
    for(int i = 0; i < 10; i ++){   //将data的数据进行重新放入,方便动图观看
        for(int j = 0; j < b[i].size(); j++){
            data[c++] = b[i].at(j);
        }
    }
    for(int i = 0; i < 10; i ++){
        //这里本想使用sort库来实现各个桶内的排序方便偷个懒的
        //可是那样就不好动图表现了,就用了直接插入排序来代替了,好像也不是很好看
        //std::sort(b[i].begin(),b[i].end());
        for(int j = 1+len; j < b[i].size()+len; j++){
            //直接插入排序
            int k;
            if(data[j] < data[j - 1]){
                int temp = data[j];
                for (k = j - 1;k>= len&&temp < data[k];k--) {
                    data[k+1] = data[k];
                    bubbleSignal(k);
                    QThread::msleep(static_cast<unsigned int>(mDelay));
                }
                data[k+1] = temp;
//                bubbleSignal(k + len);
//                QThread::msleep(static_cast<unsigned int>(mDelay));
            }
        }
        len += b[i].size();
    }
    for(int i = 0; i < length;i++){
        bubbleSignal(i);
        QThread::msleep(static_cast<unsigned int>(mDelay));
    }
}

改良后的运行结果,由于我是在桶第一次放完数据后,在重赋值回data中的,所以动图一上来才会是如此:

总结:

桶排序和基数排序挺像的,俩着可以比较的来理解和运用,另外关于桶排序的性能问题我这里就不班门弄斧了,具体大家可以看百度百科Wiki

另将所有代码打包上传,传送门在这。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章