{"id":19794534,"url":"https://github.com/shuai-xie/bitonicsort","last_synced_at":"2026-02-15T23:02:44.060Z","repository":{"id":129529664,"uuid":"102963154","full_name":"Shuai-Xie/BitonicSort","owner":"Shuai-Xie","description":"双调排序 - GAPS编程测试","archived":false,"fork":false,"pushed_at":"2019-03-03T09:26:50.000Z","size":14,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-08T15:36:31.392Z","etag":null,"topics":["algorithm","cplusplus-11","sorting-algorithms"],"latest_commit_sha":null,"homepage":"http://www.jianshu.com/p/ea4a62fdaae9","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Shuai-Xie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-09-09T15:05:49.000Z","updated_at":"2025-09-23T12:10:26.000Z","dependencies_parsed_at":"2023-06-25T23:59:24.899Z","dependency_job_id":null,"html_url":"https://github.com/Shuai-Xie/BitonicSort","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Shuai-Xie/BitonicSort","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2FBitonicSort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2FBitonicSort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2FBitonicSort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2FBitonicSort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Shuai-Xie","download_url":"https://codeload.github.com/Shuai-Xie/BitonicSort/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2FBitonicSort/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29491998,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T19:29:10.908Z","status":"ssl_error","status_checked_at":"2026-02-15T19:29:10.419Z","response_time":118,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","cplusplus-11","sorting-algorithms"],"created_at":"2024-11-12T07:13:31.424Z","updated_at":"2026-02-15T23:02:44.055Z","avatar_url":"https://github.com/Shuai-Xie.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[双调排序介绍 - 简书](http://www.jianshu.com/p/5f082115ac27)\n\n[分段双调排序 - 简书](http://www.jianshu.com/p/def12036394d)\n\n\n## 分段双调排序\n给出分成 m 段的 n 个浮点数，输入数据已按段号有序，但每段内部无序。\n用 C/C++ 编写一个分段双调排序(Bitonic sort)函数，对每一段内部的浮点数进行排序，但不要改变段间的位置。 \n\n### 1. 接口方式\n```C++\n// 分段双调排序\nvoid segmentedBitonicSort(float* data, int* seg_id, int* seg_start, int n, int m); \n```\n- data 包含需要分段排序的 n 个 float 值**（由下面的 seg_id 可知是表示多段的数据）**\n- seg_id **给出 data 中 n 个元素各自所在的段编号**\n- seg_start 共有 m+1 个元素，**前 m 个分别给出 0..m-1 共 m 个段的起始位置，seg_start[m] = n**\n- n 表示 data 中包含 n 个数据\n- m 表示 data 分为 m 段数据\n\n由题意得，m \u003c= n，因为 data 某一段可能有多于 1 个数据，这种情况下：m \u003c n\n\nseg_id 中的元素保证**单调不下降**，即对任意的 i \u003c j，seg_id[i] \u003c= seg_id[j]\nseg_id 所有元素均在 0 到 m-1 范围内。（因为是段 id，m 段就是0..m-1） \n\n### 2. 输入输出\n输入\n```C++\nfloat data[5] = {0.8, 0.2, 0.4, 0.6, 0.5};\nint seg_id[5] = {0, 0, 1, 1, 1}; // 0,1 所在位置元素对应的段id\nint seg_start[3] = {0, 2, 5}; // 表示第1段从0开始:{0.8, 0.2}，第2段从2开始:{0.4, 0.6, 0.5}\nint n = 5; // 总共5个数\nint m = 2; // 2段\n```\n\n输出\n```C++\nfloat data[5] = {0.2, 0.8, 0.4, 0.5, 0.6};\n```\n### 3. 其他要求\n\n#### 3.1 注意\n1. 必须使用双调排序算法进行排序。 \n2. 可以直接使用从网上下载的双调排序代码，但须注明出处。 \n\n#### 3.2 加分挑战（非必需）\n1. 不递归：segmentedBitonicSort 函数及其所调用的任何其他函数都不得直接或间接地进行递归。 \n1. 不调用函数：segmentedBitonicSort 不调用除标准库函数外的任何其他函数。 \n1. 内存高效：segmentedBitonicSort 及其所调用的任何其他函数都不得进行动态内存分配，包括malloc、new和静态定义的STL容器。 \n1. 可并行：segmentedBitonicSort 涉及到的所有时间复杂度O(n)以上的代码都写在for循环中，而且每个这样的for循环内部的循环顺序可以任意改变，不影响程序结果。注：自己测试时可以用rand()决定循环顺序。 \n1. 不需内存：segmentedBitonicSort 不调用任何函数（包括C/C++标准库函数）， 不使用全局变量，所有局部变量都是int、float或指针类型，C++程序不使用new关键字。 \n1. 绝对鲁棒：在输入数据中包含 NaN 时（例如```sqrt(-1.0)```)，保证除NaN以外的数据正确排序，NaN的个数保持不变。 \n\n\u003eNaN，是 Not a Number 的缩写。NaN 用于处理计算中出现的错误情况，比如 0.0 除以 0.0 或者求负数的平方根。\n\n你的程序每满足以上的一个条件都可以获得额外的加分。 \n\n#### 3.3 应提交的结果\n\n1. 算法描述； \n1. 尝试过和完成了的加分挑战； \n1. 可以独立运行的源代码； \n1. 测试数据； \n1. 性能分析； \n1. 测试的起始和完成时间以及实际使用的时间。 \n\n#### 3.4 提示\n\n1. 利用好网上资源。 \n2. 尽量利用输入中的冗余信息。 \n3. 利用好位操作。 （\u003e\u003e1）\n\n***\n## 解答\n### 1. 递归分段双调排序\n```C++\n#include \u003ciostream\u003e\n#include \u003ciomanip\u003e\n\nusing namespace std;\n\n/**\n * @param arr 小数数列\n * @param len 数列长度\n * @param w 输出单个小数的长度\n * @param precision 小数的精度\n */\nvoid printFloatArr(float *arr, int len) {\n    for (int i = 0; i \u003c len; ++i) {\n        cout \u003c\u003c setw(4) \u003c\u003c arr[i];\n    }\n    cout \u003c\u003c endl;\n}\n\nint getGreatest2nLessThan(int len) {\n    int k = 1;\n    while (k \u003c len) k = k \u003c\u003c 1; // 注意一定要加k=\n    return k \u003e\u003e 1;\n}\n\n// 任意双调排序归并\nvoid bitonicMergeAnyN(float *arr, int len, bool asd = true) {\n    if (len \u003e 1) {\n        int m = getGreatest2nLessThan(len);\n        for (int i = 0; i \u003c len - m; ++i) {\n            if (arr[i] \u003e arr[i + m] == asd)\n                swap(arr[i], arr[i + m]); // 根据asd判断是否交换\n        }\n        bitonicMergeAnyN(arr, m, asd); // 一般情况下，m \u003e len-m\n        bitonicMergeAnyN(arr + m, len - m, asd);\n    }\n}\n\n// 双调排序\nvoid bitonicSort(float *arr, int len, bool asd) { // asd 升序\n    if (len \u003e 1) {\n        int m = len / 2;\n        bitonicSort(arr, m, !asd); // 前半降序\n        bitonicSort(arr + m, len - m, asd); // 后半升序\n        bitonicMergeAnyN(arr, len, asd);\n    }\n}\n\n/**\n * 分段双调排序\n * @param data 原始数据\n * @param seg_id data 中 n 个元素各自所在的段编号\n * @param seg_start 共有 m+1 个元素，前 m 个分别给出 0..m-1 共 m 个段的起始位置，seg_start[m] = n\n * @param n data 中包含 n 个数据\n * @param m data 分为 m 段数据\n */\nvoid segmentedBitonicSort(float *data, int *seg_id, int *seg_start, int n, int m) {\n    bool asd = true;\n    for (int i = 0; i \u003c m; ++i) {\n        float *arr = data + seg_start[i]; // 数列起点\n        int len = seg_start[i + 1] - seg_start[i]; // 数列长度\n        bitonicSort(arr, len, asd);\n        cout \u003c\u003c \"段 \" \u003c\u003c i \u003c\u003c \": \";\n        printFloatArr(arr, len);\n    }\n}\n\n\nint main() {\n    float data[7] = {0.8, 0.2, 0.4, 0.6, 0.5, 0.2, 0.1}; // 数列\n    int seg_id[7] = {0, 0, 1, 1, 1, 2, 2}; // id\n    int seg_start[4] = {0, 2, 5, 7}; // 段首位置\n    int n = 7; // 数据长度\n    int m = 3; // 数据段数\n\n    segmentedBitonicSort(data, seg_id, seg_start, n, m);\n}\n```\n```\n段 0:  0.2 0.8\n段 1:  0.4 0.5 0.6\n段 2:  0.1 0.2\n```\n\n### 2. 解决NaN问题\n在归并的时候，遇到NaN型数据，就直接跳到下一个数据。\n```C++\n// 任意双调排序归并\nvoid bitonicMergeAnyN(float *arr, int len, bool asd = true) {\n    if (len \u003e 1) {\n        int m = getGreatest2nLessThan(len);\n        for (int i = 0; i \u003c len - m; ++i) {\n\n            // 解决NaN问题\n            int low = i;\n            while (arr[low] == NaN) low++;\n            int high = i + m;\n            while (arr[high] == NaN) high++;\n            // 核心代码\n\n            if (arr[low] \u003e arr[high] == asd)\n                swap(arr[low], arr[high]); // 根据asd判断是否交换\n        }\n        bitonicMergeAnyN(arr, m, asd); // 一般情况下，m \u003e len-m\n        bitonicMergeAnyN(arr + m, len - m, asd);\n    }\n}\n```\n完整代码\n```C++\n#include \u003ciostream\u003e\n#include \u003ciomanip\u003e\n#include \u003ccmath\u003e\n\n#define NaN (float)sqrt(-1.0)\n\nusing namespace std;\n\n/**\n * @param arr 小数数列\n * @param len 数列长度\n * @param w 输出单个小数的长度\n * @param precision 小数的精度\n */\nvoid printFloatArr(float *arr, int len) {\n    for (int i = 0; i \u003c len; ++i) {\n        if (arr[i] == NaN) cout \u003c\u003c setw(5) \u003c\u003c \"NaN\";\n        else cout \u003c\u003c setw(5) \u003c\u003c arr[i];\n    }\n    cout \u003c\u003c endl;\n}\n\nint getGreatest2nLessThan(int len) {\n    int k = 1;\n    while (k \u003c len) k = k \u003c\u003c 1; // 注意一定要加k=\n    return k \u003e\u003e 1;\n}\n\n// 任意双调排序归并\nvoid bitonicMergeAnyN(float *arr, int len, bool asd = true) {\n    if (len \u003e 1) {\n        int m = getGreatest2nLessThan(len);\n        for (int i = 0; i \u003c len - m; ++i) {\n\n            // 解决NaN问题\n            int low = i;\n            while (arr[low] == NaN) low++;\n            int high = i + m;\n            while (arr[high] == NaN) high++;\n\n            if (arr[low] \u003e arr[high] == asd)\n                swap(arr[low], arr[high]); // 根据asd判断是否交换\n        }\n        bitonicMergeAnyN(arr, m, asd); // 一般情况下，m \u003e len-m\n        bitonicMergeAnyN(arr + m, len - m, asd);\n    }\n}\n\n// 双调排序\nvoid bitonicSort(float *arr, int len, bool asd) { // asd 升序\n    if (len \u003e 1) {\n        int m = len / 2;\n        bitonicSort(arr, m, !asd); // 前半降序\n        bitonicSort(arr + m, len - m, asd); // 后半升序\n        bitonicMergeAnyN(arr, len, asd);\n    }\n}\n\n/**\n * 分段双调排序\n * @param data 原始数据\n * @param seg_id data 中 n 个元素各自所在的段编号\n * @param seg_start 共有 m+1 个元素，前 m 个分别给出 0..m-1 共 m 个段的起始位置，seg_start[m] = n\n * @param n data 中包含 n 个数据\n * @param m data 分为 m 段数据\n */\nvoid segmentedBitonicSort(float *data, int *seg_id, int *seg_start, int n, int m) {\n    bool asd = true;\n    for (int i = 0; i \u003c m; ++i) {\n        float *arr = data + seg_start[i];\n        int len = seg_start[i + 1] - seg_start[i];\n        bitonicSort(arr, len, asd);\n        cout \u003c\u003c \"段 \" \u003c\u003c i \u003c\u003c \": \";\n        printFloatArr(arr, len);\n    }\n}\n\n\nint main() {\n\n    float data[11] = {0.8, 0.2, 0.4, NaN, 0.6, 0.5, NaN, 0.2, 0.1, NaN, 0.01}; // 数列\n    int seg_id[11] = {0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2}; // id\n    int seg_start[4] = {0, 2, 6, 11}; // 段首位置\n    int n = 11; // 数据长度\n    int m = 3; // 数据段数\n\n    segmentedBitonicSort(data, seg_id, seg_start, n, m);\n}\n```\n```\n段 0:   0.2  0.8\n段 1:   0.4  NaN  0.5  0.6\n段 2:   NaN 0.01  0.1  NaN  0.2\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuai-xie%2Fbitonicsort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuai-xie%2Fbitonicsort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuai-xie%2Fbitonicsort/lists"}