归并排序算法思想主要是将两个有序数组合并成为一个有序数组,其关键点采用“分治思想”,“分”是二分法,将无序数组分割成为一个个有序数组,然后通过“治” 将两个有序数组合并成为一个有序数组。时间时间复杂度为为O(nlogn),空间复杂度是O(n)的常量级临时变量,是稳定排序算法。
归并排序主要实现思想:
采用“分治思想”,先“分”将整个无序数组先左边递归,再右边递归,类似二叉树先序遍历方法,将数组分为一个个有序数组;然后通过“治”将一个个有序数组通过合并merge方法组合成一个有序数组;
1.“分”vector
vectorSorts::merge(vector & nums, int start, int end) { if (start == end) //递归终止条件:如果起始下标等于结束下标,则终止递归 return { nums[start] }; // 返回左边第一个元素 int middle = (start + end) / 2; // 分治法,采用二分法,取中间下标开始左右递归,直到一个元素开始返回 auto left = merge(nums, start, middle); // 先递归左边部分,退出该层后向右递归,直到一个元素 print(left); auto right = merge(nums, middle + 1, end); // 先左边再右边递归取有序数组 return merge(left, right); // 合并两个有序数组,然后继续回退到上一层左边或者右边递归,直到整个递归结束返回为止 }
一直遍历左边部分数据,然后再返回上层遍历右边数据,这样每次左右部分个子得到一个个或组合后的有序数据组。
即下图1所示,每次都打印遍历后左边的值,可以分析出,这个递归类似二叉树里面的先序遍历,每次总是先遍历左边元素回退上一层后再遍历右边最里层元素,图2打印数据更加印证这先遍历左边再遍历右边顺序。
2.步骤1将无须数组分为一个个或一块块有序数组,这时需要将两个有序数组依次合并成一个有序数组vector
合并的关键是用两个游走下标分别遍历两个数组,将其中一个较小元素放入新创建的数组里;当其中一个数组遍历完毕后,将剩余数组放入新数组后面则完成排序;如下代码所示:
vectorSorts::merge(vector & nums1, vector & nums2) { int i1{ 0 }, i2{ 0 }; vector mergeArr(nums1.size() + nums2.size(), 0); while (i1 < nums1.size() && i2 < nums2.size()) // 分别用两个下标遍历两个数组,取较小元素放到新数组,直到其中一个数组遍历完毕为止 { //mergeArr[i1 + i2] = nums1[i1] <= nums2[i2] ? nums1[i1++] : nums2[i2++]; 这行在linux下可以,在msvc编译器段错误 if (nums1[i1] <= nums2[i2]) // 取较小元素放入新数组 { mergeArr[i1 + i2] = nums1[i1]; // ++i1; // msvc ++ 好像跟gcc编译器的实现不一样,这里放在数组里面++会段错误 } else { mergeArr[i1 + i2] = nums2[i2]; ++i2; } } while (i1 < nums1.size()) // 将剩余数组放入新数组后面 { mergeArr[i1 + i2] = nums1[i1]; ++i1; } while (i2 < nums2.size()) // 将剩余数组放入新数组后面 { mergeArr[i1 + i2] = nums2[i2]; ++i2; } return mergeArr; }
3.下面是完整的示例代码:
Sorts.h
#pragma once #include#include using namespace std; struct Sorts { void merge(vector & nums); void print(vector & nums); private: vector merge(vector & nums, int start, int end); vector merge(vector & nums1, vector & nums2); };
Sorts.cpp
#include "Sorts.h" void Sorts::merge(vector& nums) { if (nums.size() <= 1) { return; } auto tmpNums = merge(nums, 0, nums.size() - 1); nums = tmpNums; } void Sorts::print(vector & nums) { for (const auto& it : nums) cout << it << ","; cout << endl; } vector Sorts::merge(vector & nums, int start, int end) { if (start == end) //递归终止条件:如果起始下标等于结束下标,则终止递归 return { nums[start] }; // 返回左边第一个元素 int middle = (start + end) / 2; // 分治法,采用二分法,取中间下标开始左右递归,直到一个元素开始返回 auto left = merge(nums, start, middle); // 先递归左边部分,退出该层后向右递归,直到一个元素 auto right = merge(nums, middle + 1, end); // 先左边再右边递归取有序数组 return merge(left, right); // 合并两个有序数组,然后继续回退到上一层左边或者右边递归,直到整个递归结束返回为止 } vector Sorts::merge(vector & nums1, vector & nums2) { int i1{ 0 }, i2{ 0 }; vector mergeArr(nums1.size() + nums2.size(), 0); while (i1 < nums1.size() && i2 < nums2.size()) // 分别用两个下标遍历两个数组,取较小元素放到新数组,直到其中一个数组遍历完毕为止 { //mergeArr[i1 + i2] = nums1[i1] <= nums2[i2] ? nums1[i1++] : nums2[i2++]; 这行在linux下可以,在msvc编译器段错误 if (nums1[i1] <= nums2[i2]) // 取较小元素放入新数组 { mergeArr[i1 + i2] = nums1[i1]; // ++i1; // msvc ++ 好像跟gcc编译器的实现不一样,这里放在数组里面++会段错误 } else { mergeArr[i1 + i2] = nums2[i2]; ++i2; } } while (i1 < nums1.size()) // 将剩余数组放入新数组后面 { mergeArr[i1 + i2] = nums1[i1]; ++i1; } while (i2 < nums2.size()) // 将剩余数组放入新数组后面 { mergeArr[i1 + i2] = nums2[i2]; ++i2; } return mergeArr; }
main.cpp
#include#include "Sorts.h" using namespace std; int main() { vector nums = { 2,0,1,6,8,10,5,99,87,333,2,0,1 }; Sorts sorts; sorts.print(nums); sorts.merge(nums); sorts.print(nums); return 1; }
输出结果:



