归并排序
(1)算法介绍
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用,归并排序将两个已经有序的序列合并成一个有序的序列。
思路:假设我们有一个没有排好序的序列,那么我们首先使用分割的方法将这个序列分割成一个个已经排好序的子序列(当一个序列只有一个元素时,该序列自然是有序的)。然后再利用归并的方法将一个个有序的子序列合并成排好序的序列。
(2)算法执行过程
下面就一常用的二路归并排序讲解分割和合并的过程,看下图
待排序列为:14 12 15 13 11 16
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*该函数将数组下标范围[l1,r1]和[l2,r2]的有序序列合并成一个有序序列*/
void merge(vector<int>& nums, int l1, int r1, int l2, int r2 ) {
int i = l1; //左半部分起始位置
int j = l2; //右半部分起始位置
int n = (r1 - l1 + 1) + (r2 - l2 + 1); //要合并的元素个数
vector<int> temp(n); //辅助数组
int k = 0; //辅助数组其起始位置
while (i <= r1&&j <= r2) { //挑选两部分中最小的元素放入辅助数组中
if (nums[i] < nums[j])
temp[k++] = nums[i++];
else
temp[k++] = nums[j++];
}
//如果还有剩余,直接放入到辅助数组中
while (i <= r1)
temp[k++] = nums[i++];
while (j <= r2)
temp[k++] = nums[j++];
//更新原始数组元素
for (int i = 0; i < n;i++)
{
nums[l1 + i] = temp[i];
}
}
/*二路归并排序(递归实现)*/
void MergeSort(vector<int>& nums,int start, int end) {
if (start < end) {
int mid = (start + end) >> 1; //分割序列
MergeSort(nums, start, mid); //对序列左半部分进行规并排序
MergeSort(nums, mid + 1, end); //对序列右半部分进行规并排序
merge(nums, start, mid, mid + 1, end); //合并已经有序的两个序列
}
}
/*二路归并排序(迭代实现)*/
void MergeSort1(vector<int>& nums, int start, int end)
{
int n = nums.size();
if (start < end) {
//step为组内元素个数,step/2为左子区间元素个数
for (int step = 2; step/2 <n; step *= 2) {
//每step个元素一组,组内前step/2和后step/2个元素进行合并
for (int i = 0; i < n; i += step) {
int mid = i + step / 2 - 1; //左子区间元素个数为step/2
if(mid+1<n) //右子区间存在元素个数则合并
//左子区间为[i,mid],右子区间为[mid+1, min(i+step-1, n-1)]
merge(nums, i, mid, mid + 1, min(i + step - 1, n-1));
}
}
}
}
int main() {
vector<int> nums{ 1,4,3,2,5,6,3 };
MergeSort(nums,0,6);
// MergeSort1(nums, 0, 6);
for (auto x : nums)
cout << x << " ";
cout << endl;
return 0;
}
运行结果如下
复杂度分析
(1)时间复杂度
最坏情况=最好情况=平均情况=O(nlogn)
(2)空间复杂度
需要额外大小一样的辅助数组,因此空间复杂度为O(n)。