归并排序(一)——递归排序

归并的思想和前面说的快排比较类似,

 

快排是先通过单趟排序,产生一个分界点,然后分界点的两侧重新开始单趟排序

归并是直接将以数组的中心位置作为分界点,不断取中间位置,分成两个小区间,直到无法分解

核心思路:先分解左半部分,然后排序

                  再分解右半部分,然后排序

一、算法基本思路

1、先分解

将数组分解至无法继续往下分解,如下

归并排序(一)——递归排序_第1张图片

2、再排序

排序时,从最底层开始排序

(1)9 可以看作一个数组arr1 ,3  可以看作一个数组arr2  

(2)3比9小,3先放入临时数组,由于arr2数组结束了,所以直接把9放到临时数组的末尾

    归并排序(一)——递归排序_第2张图片

(3)然后把tmp数组的值去替换 原数组中对应位置的值

​​​​​​​           ​​​​​​​归并排序(一)——递归排序_第3张图片

   3、整体过程

上面的数组更新过程可能有点抽象

先调整 9  3(倒数第一层)——会变成3 9

归并排序(一)——递归排序_第4张图片               

                 ​​​​​​​归并排序(一)——递归排序_第5张图片                                            归并排序(一)——递归排序_第6张图片

 归并排序(一)——递归排序_第7张图片           

 后续过程

归并排序(一)——递归排序_第8张图片

后续是按照红色、蓝色、橙色的区间排序,左边就排序结束了

然后再对右边开始排序,同样也是从底层向上排序

二、递归排序代码实现

1、单层排序

归并排序(一)——递归排序_第9张图片归并排序(一)——递归排序_第10张图片归并排序(一)——递归排序_第11张图片

void SingleLevelSort(int* a,int left,int right)
{
    //第一个区间的起始位置
    int begin1 = left, end1 = mid;
    //第二个区间的起始位置
	int begin2 = mid + 1, end2 = right;
	//tmp 用于临时存放排列好的数据
	int size = right - left + 1;
	int* tmp = new int[size];

	int p = 0;
	while (begin1 <= end1 && begin2 <= end2)
	{
        //begin2小,则begin2放入临时数组,begin2向后移动一位
		if (a[begin1]>a[begin2])
		{
			tmp[p++] = a[begin2++];
		}
		else
		{
			tmp[p++] = a[begin1++];
		}
	}

	//将还有剩余的区间,拼接到tmp的后面
	while (begin1 <= end1)
	{
		tmp[p++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[p++] = a[begin2++];
	}

	//当前区间的排序结束,将tmp中的数据更新到原数组
	for (size_t i = 0; i < size; i++)
	{
        //注意 a 存放数据的范围是 [left,right]
        // tmp存放数据的范围是  [0,size-1]
		a[left+i] = tmp[i];
	}

	delete[] tmp;
	tmp = nullptr;
}

2、递归排序

归并排序(一)——递归排序_第12张图片

void MergeSort(int* a,int left,int right) {
    //到达底端的只剩一个数的时候,无法分解,返回上一级
	if (left>=right)
	{
		return;
	}

    //取排序的中间位置,分成两个小区间
	int mid = (left + right) / 2;
	//左区间,向左分解
	MergeSort(a, left, mid);
	//右区间,向右分解
	MergeSort(a, mid + 1, right);

    //只有分解到达底端的时候,才会开始调用这个函数,然后一步步向上排序
    SingleLevelSort(a,left,right);
}

三、代码测试

int main()
{
	int arr[] = { 9,3,4,6,2,5,1,7,8};
	MergeSort(arr, 0, sizeof(arr) / sizeof(arr[0])-1);

	for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	return 0;
}

 

四、时间复杂度

从第二部分的向下分解可以看出,逻辑结构类似于二叉树

====》时间复杂度:O(N*log N)

你可能感兴趣的:(数据结构,排序算法,算法,数据结构)