https://blog.csdn.net/Windows_Defender/article/details/85077231
https://blog.csdn.net/ASCIIdragon/article/details/84029878
https://blog.csdn.net/YF_Li123/article/details/75072991
算法思想:
主要利用分治算法思想:
将需要排序的元素分成大概相等的2个子集合,
即左侧和右侧,生成的集合再次通过Mergesort算法进行递归分割,
直到它们分解为每个集合中的单个元素。
分别给2个子集合进行排序,它将每次比较中较小的元素插入到临时数组中,再选择较小元素的下一个,
通过比较,再选择两者中的较小元素放至临时数组,
最终将2个排好序的子集合合并成一个有序的集合。
主要分为两个阶段:拆分和合并
时间复杂度:无论最好情况还是最坏情况均是O(nlogn);、
#include<iostream>
using namespace std;
void Merge(int* a, int left, int mid, int right);
void MergeSort(int* a, int start, int end);
int main(void) {
int a[8] = { 46,30,82,90,56,17,95,15 };
MergeSort(a, 0, 7);
for (int i = 0; i < 8; i++) {
cout << a[i] << " ";
}
getchar();
}
/**
* 拆分阶段,理解递归
*将数组中的元素分成2部分,每个部分再次划分,直至只剩下单个元素,再进行排序
* @param a 待拆分的数组
* @param start 数组的开始下标
* @param end 数组的结束下标
*/
void MergeSort(int* a, int start, int end) {
if (start < end) {//当子序列中只有一个元素时结束递归,也就是start==end
int mid = (start + end) / 2;
//对左侧子序列进行递归拆分
MergeSort(a, start, mid);
//对右侧子序列进行递归拆分
MergeSort(a, mid + 1, end);
//合并
Merge(a, start, mid + 1, end);//当左右两边都不能再分了以后,才归并在一起
}
}
/**
* 合并阶段
* @param a 待合并的数组
* @param left 左侧的数组首下标
* @param mid 数组中间元素下标
* @param right 右侧的数组首下标
*/
/*
合并理解:
传进数组a,以及最左边left,和中间mid,以及最右面right。
首先定义一个一个指针, temp,也就是临时数组。数组大小,为传如数组大小。
然后通过while循环,来判断传入的数组,左右两端进行判断。
例如:
46,30,82,90,56,17,95,15
传入的时候,数组已经变成
30 46 82 90 15 17 56 95
此时通过while循环
判断 a[left_1] < a[mid_1]。
也就是a[0] 与 a[4] 。即30与15判断。30 > 15
此时执行 temp[k++] = a[mid_1++]等同于 temp[k] = a[mid_1], k++, mid_1++
重复执行,直至不满足while循环内的条件结束循环。
不满足循环时, 此时temp数组应该变成 15 17 30 46 56 82 90
剩下右边数组的最右边一个数95。此时mid等于7 ,left_1 = 3 ,right = 7
执行下面的两个while循环,
while (mid_1 <= right),满足7<=7
则将 temp[k++] = a[mid_1++];也就是将95加进数组
while (left_1 < mid)不满足
for (int n = 0; n < num; n++)
将排序好的数组,赋值给原数组
*/
void Merge(int* a , int left,int mid,int right) {
int left_1 = left;//left_1等于左边索引
int mid_1 = mid;//mid_1等于中间索引
int right_1 = right;//right_1等于右边索引
int num = right - left + 1;//num等于要声明的临时数组大小
int k = 0;
int* temp = new int[num];
while (left_1 < mid && mid_1 <= right) {//当左边小于中间,中间小于右边时
if (a[left_1] < a[mid_1]) {
temp[k++] = a[left_1++]; //left_1++是先执行表达式后再自增,执行表达式时使用的是left_1的原值。
}
else {
temp[k++] = a[mid_1++];
}
}
//left_1检测完,mid_1还没有,直接将mid_1剩下的元素加到合并数组中
while (mid_1 <= right) {
temp[k++] = a[mid_1++];
}
//mid_1检测完,left_1还没有,直接将left_1剩下的元素加到合并数组中
while (left_1 < mid) {
temp[k++] = a[left_1++];
}
//复制回原数组
for (int n = 0; n < num; n++) {
a[left+n] = temp[n];
}
}