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

另將所有代碼打包上傳,傳送門在這。

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