合并排序

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
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];
	}
	

}

你可能感兴趣的:(算法设计与分析)