分段雙調(diào)排序

分段雙調(diào)排序 - Shuai-Xie -Github

問(wèn)題說(shuō)明

給出分成 m 段的 n 個(gè)浮點(diǎn)數(shù)唆铐,輸入數(shù)據(jù)已按段號(hào)有序勋又,但每段內(nèi)部無(wú)序没炒。
用 C/C++ 編寫一個(gè)分段雙調(diào)排序(Bitonic sort)函數(shù)缔俄,對(duì)每一段內(nèi)部的浮點(diǎn)數(shù)進(jìn)行排序个粱,但不要改變段間的位置蝎宇。

1. 接口方式

// 分段雙邊排序
void segmentedBitonicSort(float* data, int* seg_id, int* seg_start, int n, int m); 
  • data 包含需要分段排序的 n 個(gè) float 值(由下面的 seg_id 可知是表示多段的數(shù)據(jù))
  • seg_id 給出 data 中 n 個(gè)元素各自所在的段編號(hào)
  • seg_start 共有 m+1 個(gè)元素畏妖,前 m 個(gè)分別給出 0..m-1 共 m 個(gè)段的起始位置绩聘,seg_start[m] = n
  • n 表示 data 中包含 n 個(gè)數(shù)據(jù)
  • m 表示 data 分為 m 段數(shù)據(jù)

由題意得亲澡,m <= n钦扭,因?yàn)?data 某一段可能有多于 1 個(gè)數(shù)據(jù),這種情況下:m < n

seg_id 中的元素保證單調(diào)不下降床绪,即對(duì)任意的 i < j客情,seg_id[i] <= seg_id[j]
seg_id 所有元素均在 0 到 m-1 范圍內(nèi)。(因?yàn)槭嵌?id癞己,m 段就是0..m-1)

2. 輸入輸出

輸入

float data[5] = {0.8, 0.2, 0.4, 0.6, 0.5};
int seg_id[5] = {0, 0, 1, 1, 1}; // 0,1 所在位置元素對(duì)應(yīng)的段id
int seg_start[3] = {0, 2, 5}; // 表示第1段從0開(kāi)始:{0.8, 0.2}膀斋,第2段從2開(kāi)始:{0.4, 0.6, 0.5}
int n = 5; // 總共5個(gè)數(shù)
int m = 2; // 2段

輸出

float data[5] = {0.2, 0.8, 0.4, 0.5, 0.6};

3. 其他要求

3.1 注意
  1. 必須使用雙調(diào)排序算法進(jìn)行排序。
  2. 可以直接使用從網(wǎng)上下載的雙調(diào)排序代碼痹雅,但須注明出處仰担。
3.2 加分挑戰(zhàn)(非必需)
  1. 不遞歸:segmentedBitonicSort 函數(shù)及其所調(diào)用的任何其他函數(shù)都不得直接或間接地進(jìn)行遞歸。
  2. 不調(diào)用函數(shù):segmentedBitonicSort 不調(diào)用除標(biāo)準(zhǔn)庫(kù)函數(shù)外的任何其他函數(shù)绩社。
  3. 內(nèi)存高效:segmentedBitonicSort 及其所調(diào)用的任何其他函數(shù)都不得進(jìn)行動(dòng)態(tài)內(nèi)存分配摔蓝,包括malloc赂苗、new和靜態(tài)定義的STL容器。
  4. 可并行:segmentedBitonicSort 涉及到的所有時(shí)間復(fù)雜度O(n)以上的代碼都寫在for循環(huán)中贮尉,而且每個(gè)這樣的for循環(huán)內(nèi)部的循環(huán)順序可以任意改變拌滋,不影響程序結(jié)果。注:自己測(cè)試時(shí)可以用rand()決定循環(huán)順序绘盟。
  5. 不需內(nèi)存:segmentedBitonicSort 不調(diào)用任何函數(shù)(包括C/C++標(biāo)準(zhǔn)庫(kù)函數(shù))鸠真, 不使用全局變量,所有局部變量都是int龄毡、float或指針類型吠卷,C++程序不使用new關(guān)鍵字。
  6. 絕對(duì)魯棒:在輸入數(shù)據(jù)中包含 NaN 時(shí)(例如sqrt(-1.0))沦零,保證除NaN以外的數(shù)據(jù)正確排序祭隔,NaN的個(gè)數(shù)保持不變。

NaN路操,是 Not a Number 的縮寫疾渴。
NaN 用于處理計(jì)算中出現(xiàn)的錯(cuò)誤情況,比如 0.0 除以 0.0 或者求負(fù)數(shù)的平方根屯仗。

你的程序每滿足以上的一個(gè)條件都可以獲得額外的加分搞坝。

3.3 應(yīng)提交的結(jié)果
  1. 算法描述;
  2. 嘗試過(guò)和完成了的加分挑戰(zhàn)魁袜;
  3. 可以獨(dú)立運(yùn)行的源代碼桩撮;
  4. 測(cè)試數(shù)據(jù);
  5. 性能分析峰弹;
  6. 測(cè)試的起始和完成時(shí)間以及實(shí)際使用的時(shí)間店量。
3.4 提示
  1. 利用好網(wǎng)上資源。
  2. 盡量利用輸入中的冗余信息鞠呈。
  3. 利用好位操作融师。 (>>1)

解答

1. 遞歸分段雙調(diào)排序

#include <iostream>
#include <iomanip>

using namespace std;

/**
 * @param arr 小數(shù)數(shù)列
 * @param len 數(shù)列長(zhǎng)度
 * @param w 輸出單個(gè)小數(shù)的長(zhǎng)度
 * @param precision 小數(shù)的精度
 */
void printFloatArr(float *arr, int len) {
    for (int i = 0; i < len; ++i) {
        cout << setw(4) << arr[i];
    }
    cout << endl;
}

int getGreatest2nLessThan(int len) {
    int k = 1;
    while (k < len) k = k << 1; // 注意一定要加k=
    return k >> 1;
}

// 任意雙調(diào)排序歸并
void bitonicMergeAnyN(float *arr, int len, bool asd = true) {
    if (len > 1) {
        int m = getGreatest2nLessThan(len);
        for (int i = 0; i < len - m; ++i) {
            if (arr[i] > arr[i + m] == asd)
                swap(arr[i], arr[i + m]); // 根據(jù)asd判斷是否交換
        }
        bitonicMergeAnyN(arr, m, asd); // 一般情況下,m > len-m
        bitonicMergeAnyN(arr + m, len - m, asd);
    }
}

// 雙調(diào)排序
void bitonicSort(float *arr, int len, bool asd) { // asd 升序
    if (len > 1) {
        int m = len / 2;
        bitonicSort(arr, m, !asd); // 前半降序
        bitonicSort(arr + m, len - m, asd); // 后半升序
        bitonicMergeAnyN(arr, len, asd);
    }
}

/**
 * 分段雙調(diào)排序
 * @param data 原始數(shù)據(jù)
 * @param seg_id data 中 n 個(gè)元素各自所在的段編號(hào)
 * @param seg_start 共有 m+1 個(gè)元素蚁吝,前 m 個(gè)分別給出 0..m-1 共 m 個(gè)段的起始位置旱爆,seg_start[m] = n
 * @param n data 中包含 n 個(gè)數(shù)據(jù)
 * @param m data 分為 m 段數(shù)據(jù)
 */
void segmentedBitonicSort(float *data, int *seg_id, int *seg_start, int n, int m) {
    bool asd = true;
    for (int i = 0; i < m; ++i) {
        float *arr = data + seg_start[i]; // 數(shù)列起點(diǎn)
        int len = seg_start[i + 1] - seg_start[i]; // 數(shù)列長(zhǎng)度
        bitonicSort(arr, len, asd);
        cout << "段 " << i << ": ";
        printFloatArr(arr, len);
    }
}


int main() {
    float data[7] = {0.8, 0.2, 0.4, 0.6, 0.5, 0.2, 0.1}; // 數(shù)列
    int seg_id[7] = {0, 0, 1, 1, 1, 2, 2}; // id
    int seg_start[4] = {0, 2, 5, 7}; // 段首位置
    int n = 7; // 數(shù)據(jù)長(zhǎng)度
    int m = 3; // 數(shù)據(jù)段數(shù)

    segmentedBitonicSort(data, seg_id, seg_start, n, m);
}
段 0:  0.2 0.8
段 1:  0.4 0.5 0.6
段 2:  0.1 0.2

2. 解決NaN問(wèn)題

在歸并的時(shí)候,遇到NaN型數(shù)據(jù)窘茁,就直接跳到下一個(gè)數(shù)據(jù)疼鸟。

// 任意雙調(diào)排序歸并
void bitonicMergeAnyN(float *arr, int len, bool asd = true) {
    if (len > 1) {
        int m = getGreatest2nLessThan(len);
        for (int i = 0; i < len - m; ++i) {

            // 解決NaN問(wèn)題
            int low = i;
            while (arr[low] == NaN) low++;
            int high = i + m;
            while (arr[high] == NaN) high++;
            // 核心代碼

            if (arr[low] > arr[high] == asd)
                swap(arr[low], arr[high]); // 根據(jù)asd判斷是否交換
        }
        bitonicMergeAnyN(arr, m, asd); // 一般情況下,m > len-m
        bitonicMergeAnyN(arr + m, len - m, asd);
    }
}

完整代碼

#include <iostream>
#include <iomanip>
#include <cmath>

#define NaN (float)sqrt(-1.0)

using namespace std;

/**
 * @param arr 小數(shù)數(shù)列
 * @param len 數(shù)列長(zhǎng)度
 * @param w 輸出單個(gè)小數(shù)的長(zhǎng)度
 * @param precision 小數(shù)的精度
 */
void printFloatArr(float *arr, int len) {
    for (int i = 0; i < len; ++i) {
        if (arr[i] == NaN) cout << setw(5) << "NaN";
        else cout << setw(5) << arr[i];
    }
    cout << endl;
}

int getGreatest2nLessThan(int len) {
    int k = 1;
    while (k < len) k = k << 1; // 注意一定要加k=
    return k >> 1;
}

// 任意雙調(diào)排序歸并
void bitonicMergeAnyN(float *arr, int len, bool asd = true) {
    if (len > 1) {
        int m = getGreatest2nLessThan(len);
        for (int i = 0; i < len - m; ++i) {

            // 解決NaN問(wèn)題
            int low = i;
            while (arr[low] == NaN) low++;
            int high = i + m;
            while (arr[high] == NaN) high++;

            if (arr[low] > arr[high] == asd)
                swap(arr[low], arr[high]); // 根據(jù)asd判斷是否交換
        }
        bitonicMergeAnyN(arr, m, asd); // 一般情況下庙曙,m > len-m
        bitonicMergeAnyN(arr + m, len - m, asd);
    }
}

// 雙調(diào)排序
void bitonicSort(float *arr, int len, bool asd) { // asd 升序
    if (len > 1) {
        int m = len / 2;
        bitonicSort(arr, m, !asd); // 前半降序
        bitonicSort(arr + m, len - m, asd); // 后半升序
        bitonicMergeAnyN(arr, len, asd);
    }
}

/**
 * 分段雙調(diào)排序
 * @param data 原始數(shù)據(jù)
 * @param seg_id data 中 n 個(gè)元素各自所在的段編號(hào)
 * @param seg_start 共有 m+1 個(gè)元素空镜,前 m 個(gè)分別給出 0..m-1 共 m 個(gè)段的起始位置,seg_start[m] = n
 * @param n data 中包含 n 個(gè)數(shù)據(jù)
 * @param m data 分為 m 段數(shù)據(jù)
 */
void segmentedBitonicSort(float *data, int *seg_id, int *seg_start, int n, int m) {
    bool asd = true;
    for (int i = 0; i < m; ++i) {
        float *arr = data + seg_start[i];
        int len = seg_start[i + 1] - seg_start[i];
        bitonicSort(arr, len, asd);
        cout << "段 " << i << ": ";
        printFloatArr(arr, len);
    }
}


int main() {

    float data[11] = {0.8, 0.2, 0.4, NaN, 0.6, 0.5, NaN, 0.2, 0.1, NaN, 0.01}; // 數(shù)列
    int seg_id[11] = {0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2}; // id
    int seg_start[4] = {0, 2, 6, 11}; // 段首位置
    int n = 11; // 數(shù)據(jù)長(zhǎng)度
    int m = 3; // 數(shù)據(jù)段數(shù)

    segmentedBitonicSort(data, seg_id, seg_start, n, m);
}
段 0:   0.2  0.8
段 1:   0.4  NaN  0.5  0.6
段 2:   NaN 0.01  0.1  NaN  0.2
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吴攒,隨后出現(xiàn)的幾起案子张抄,更是在濱河造成了極大的恐慌,老刑警劉巖洼怔,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件署惯,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡镣隶,警方通過(guò)查閱死者的電腦和手機(jī)极谊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)安岂,“玉大人轻猖,你說(shuō)我怎么就攤上這事∮蚰牵” “怎么了咙边?”我有些...
    開(kāi)封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)次员。 經(jīng)常有香客問(wèn)我败许,道長(zhǎng),這世上最難降的妖魔是什么淑蔚? 我笑而不...
    開(kāi)封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任市殷,我火速辦了婚禮,結(jié)果婚禮上刹衫,老公的妹妹穿的比我還像新娘醋寝。我一直安慰自己,他們只是感情好绪妹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著柿究,像睡著了一般邮旷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝇摸,一...
    開(kāi)封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天婶肩,我揣著相機(jī)與錄音,去河邊找鬼貌夕。 笑死律歼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的啡专。 我是一名探鬼主播险毁,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了畔况?” 一聲冷哼從身側(cè)響起鲸鹦,我...
    開(kāi)封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎跷跪,沒(méi)想到半個(gè)月后馋嗜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吵瞻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年葛菇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橡羞。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡眯停,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尉姨,到底是詐尸還是另有隱情庵朝,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布又厉,位于F島的核電站九府,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏覆致。R本人自食惡果不足惜侄旬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望煌妈。 院中可真熱鬧儡羔,春花似錦、人聲如沸璧诵。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)之宿。三九已至族操,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間比被,已是汗流浹背色难。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留等缀,地道東北人枷莉。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像尺迂,于是被迫代替她去往敵國(guó)和親笤妙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冒掌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,160評(píng)論 30 470
  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序危喉,而外部排序是因排序的數(shù)據(jù)很大宋渔,一次不能容納全部...
    蟻前閱讀 5,188評(píng)論 0 52
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,260評(píng)論 0 2
  • 概率需求模型:?jiǎn)纹谟嗀?美式足球在美國(guó)非常受歡迎,不管是職業(yè)聯(lián)賽辜限、大學(xué)皇拣、中學(xué)、甚至小學(xué)都熱衷于這個(gè)運(yùn)動(dòng)薄嫡,非常有代表...
    供應(yīng)鏈NSGG閱讀 1,045評(píng)論 0 1
  • 幾件事情: (1)毫深、寄快遞吩坝,給羅總發(fā)短信,給肖老師發(fā)短信哑蔫,給姚哥發(fā)短信钉寝,給輝哥發(fā)短信,給崔楊發(fā)短信闸迷,給朱總發(fā)短信嵌纲,...
    笑曰閱讀 212評(píng)論 0 0