前置知识:讲解019-算法笔试中处理输入和输出,讲解020-递归和master公式
注意:有些资料说可以用原地归并排序,把额外空间复杂度变成O(1),不要浪费时间去学。因为原地归并排序确实可以省空间,但是会把复杂度变成O(n^2)
归并排序 递:左,有序 递:右,有序 整合(非):左,右呵呵哒的瞎想(可以不看):f(0,0)是6,f(1,1)是4,只有获得了这两个数值,才能合并成f(0,1),也就是[4,6]。而这个过程正好是后序遍历。左右中
// 递归方法 void mergeSort(vector<int>& arr, int left, int right) { if (left == right) return; int mid = (left + right) / 2; mergeSort(arr, left, mid); // 左 mergeSort(arr, mid + 1, right); // 右 merge(arr, left, mid, right); // 中 }
最后再刷回原数组
- void merge(vector<int>& arr,int left, int mid, int right) {
- int n = right - left + 1;
- vector<int> help(n,0);
- int i = 0;
- int a = left;
- int b = mid + 1;
- while (a <= mid && b <= right) {
- help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
- }
- // 左侧指针,右侧指针,必有一个越界,另一个不越界
- while (a <= mid) {
- help[i++] = arr[a++];
- }
- while (b <= right) {
- help[i++] = arr[b++];
- }
- for (i = 0; i
// 把 help 里面的数据重新刷回到原数组arr - arr[i+left] = help[i];
- }
- }
(1)归并排序递归版
- // 递归方法
- void mergeSort(vector<int>& arr, int left, int right) {
- if (left == right) return;
- int mid = (left + right) / 2;
- mergeSort(arr, left, mid);
- mergeSort(arr, mid + 1, right);
- merge(arr, left, mid, right);
- }
(2)归并排序非递归版
- // 归并排序非递归版
- // 时间复杂度:O(n * logn)
- // 空间复杂度:O(n)
- void mergeSort2(vector<int>& arr) {
- int n = arr.size();
- // 一共发生O(logn)次
- for (int left, mid, right, step = 1; step < n; step <<= 1) {
- // 内部分组merge,时间复杂度:O(n)
- left = 0;
- while (left < n) {
- mid = left + step - 1;
- if (mid + 1 >= n) {
- // 已经没有右侧了
- break;
- }
- // 有右侧,求右侧的右边界
- right = min(left + (step << 1) - 1, n - 1);
- // left ... mid mid+1 ... right
- // left ... mid mid+1 ... right
- // left ... mid mid+1 ... right
- merge(arr,left, mid, right);
- left = right + 1;
- }
- }
- }
完整代码:
- #include
- #include
- using namespace std;
-
- void merge(vector<int>& arr,int left, int mid, int right) {
- int n = right - left + 1;
- vector<int> help(n,0);
- int i = 0;
- int a = left;
- int b = mid + 1;
- while (a <= mid && b <= right) {
- help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
- }
- // 左侧指针,右侧指针,必有一个越界,另一个不越界
- while (a <= mid) {
- help[i++] = arr[a++];
- }
- while (b <= right) {
- help[i++] = arr[b++];
- }
- for (i = 0; i
// 把 help 里面的数据重新刷回到原数组arr - arr[i+left] = help[i];
- }
- }
-
- /*
- 归并排序递归版
- 假设left...right一共 n 个数
- T(n) = 2 * T(n/2) + O(n)
- a = 2,b = 2,c = 1
- 根据master公式,时间复杂度:O(n * logn)
- 空间复杂度:O(n)
- */
- // 递归方法
- void mergeSort(vector<int>& arr, int left, int right) {
- if (left == right) return;
- int mid = (left + right) / 2;
- mergeSort(arr, left, mid);
- mergeSort(arr, mid + 1, right);
- merge(arr, left, mid, right);
- }
-
- // 归并排序非递归版
- // 时间复杂度:O(n * logn)
- // 空间复杂度:O(n)
- void mergeSort2(vector<int>& arr) {
- int n = arr.size();
- // 一共发生O(logn)次
- for (int left, mid, right, step = 1; step < n; step <<= 1) {
- // 内部分组merge,时间复杂度:O(n)
- left = 0;
- while (left < n) {
- mid = left + step - 1;
- if (mid + 1 >= n) {
- // 已经没有右侧了
- break;
- }
- // 有右侧,求右侧的右边界
- right = min(left + (step << 1) - 1, n - 1);
- // left ... mid mid+1 ... right
- // left ... mid mid+1 ... right
- // left ... mid mid+1 ... right
- merge(arr,left, mid, right);
- left = right + 1;
- }
- }
- }
-
- int main() {
- vector<int> arr = { 6,4,2,3,9,4};
- int n = arr.size();
- mergeSort(arr, 0, n - 1);
- //mergeSort2(arr);
- for (int i = 0; i < n; i++) {
- cout << " " << arr[i] << " " << endl;
- }
- system("pause");
- return 0;
- }
完整图:
参考和推荐视频: