跳到主要内容

归并排序

介绍

归并排序 (Merge Sort),其中体现了 分而治之 的编程思想, 其时间复杂度为 O(nlogn)O(n\log_{}{n}), 空间复杂度为 O(n)O(n)

它与 快速排序 是有点类似的,但是又不完全是,见表:

归并排序快速排序
平均时间复杂度O(nlogn)O(n\log_{}{n})O(nlogn)O(n\log_{}{n})
空间复杂度O(n)O(n)O(nlogn)O(n\log_{}{n})
最优时间复杂度O(nlogn)O(n\log_{}{n})O(n2)O(n^{2})
最坏时间复杂度O(nlogn)O(n\log_{}{n})O(n2)O(n^{2})
稳定性稳定不稳定

尽管快速排序的空间复杂度要更小,但是其稳定性都远远不如归并排序 (尤其是处理大量数据时)

思路

合并

首先,假设我们有两个有序数组 [1,3,5][2,4], 需要将其合并为有序数组,我们可以用到 指针

比较

然后,我们使用指针对数组每个元素进行比较,小的就被放入了 ans

主要流程

定义三个指针 ijk、三个数组为arr1arr2ans,运行流程如下:

代码实现

/**
* 合并排序实例程序。
* @author CoolCLK
*/

#include <iostream>
#include <vector>
#include <string>

/**
* 合并两个有序数组。
* @author CoolCLK
*/
template<typename T>
std::vector<T> merge(std::vector<T> arr, std::vector<T> a, std::vector<T> b) {
size_t i = 0, j = 0, k = 0;

while (i < a.size() && j < b.size()) {
if (a[i] < b[j]) {
arr[k] = a[i];
i++;
} else {
arr[k] = b[j];
j++;
}
k++;
}

while (i < a.size()) {
arr[k] = a[i];
i++;
k++;
}

while (j < b.size()) {
arr[k] = b[j];
j++;
k++;
}
}

/**
* 对数组进行合并排序。
* @author CoolCLK
*/
template<typename T>
void merge_sort(std::vector<T> arr) {
if (arr.size() <= 1) {
return arr;
}
size_t mid = arr.size() / 2;
std::vector<T> left(arr.begin(), arr.begin() + mid);
std::vector<T> right(arr.begin() + mid, arr.end());
if (left.size() > 1) {
left = merge_sort(left);
}
if (right.size() > 1) {
right = merge_sort(right);
}
merge(arr, left, right);
}

/**
* 主函数,可用于通用数组输入、输出 CLI 模板。
* @author CoolCLK
*/
int main() {
std::vector<int> array(0);

std::cout << "[";
while (true) {
std::cout << "\e[s"; // 保存光标位置
std::string input;
std::cin >> input;
std::cout << "\e[u"; // 恢复光标位置
if (input == "]") {
std::cout << "\e[1D" << "]" << " " << std::endl; // 往前移动消除原有输入
break;
}
std::cout << input << ",";
int num = std::stoi(input);
array.emplace_back(num);
}

merge_sort(array);
std::cout << "[";
for (int el : array) {
std::cout << el << ",";
}
std::cout << (array.size() > 0 ? "\e[1D" : "") << "]" << std::endl;

return 0;
}