0
点赞
收藏
分享

微信扫一扫

算法:分治法之合并排序

西红柿上校 2022-03-11 阅读 239

合并排序算法思想:

先将无序序列利用二分法划分为子序列,直至每个子序列只有一个元素(单个元素就是有序),然后再对有序子序列两两进行合并排序。

合并方法是循环地将两个有序子序列当前的首元素进行比较,较小的元素取出,置入合并序列(这就是合并排序O(n)的辅助空间花销的来源,建立了一个新的空数组来接收排好序的子序列)的左边空置位,直至所有元素置入合并序列

怎么划分就怎么合并!!!!

 (截图自B站up主:请叫我AXin 的视频)

解释:

     (0+8)/ 2 = 4  所以下标为4及左边的元素作为一个子数组,下标大于4的元素作为另一个子数组

       同理,(0+4)/  2 = 2  所以 下标为 0 1 2 的元素作为一个子数组,下标为3 4 的作为另一个子数组

     (0+2)/ 2 = 1 所以 下标为 0 1 的元素作为一个子数组,下标为2的元素作为另一个子数组,因为这个子数组只有一个元素,所以他就是有序数组,等待合并就行。

     (0+1)/ 2 = 0 所以下标为0 的元素作为一个子数组,下标为1 的又作为一个子数组,也划分完毕了。

      右边的元素划分也同理。

      都划分完毕后,就开始合并,怎么划分就怎么合并。

      小的数就放前面,例如子数组2 5 9   和子数组 7  12:

一开始两个指针分别指向2,7。因为2<7,所以2拎出来,指到5,5<7,拎出来,指针继续走指到9,9>7,所以7拎出来,现在合并序列为 2 5 7,第一个子数组没数了,加入12,就排好了

#include <iostream>
using namespace std;
void Merge(int arr[], int left, int mid,int right)
{
	int* B = new int[right - left + 1];   //开辟一个辅助空间接收排好序的元素
	int i = left;   //将两个子数组的首元素下标分别赋值给i和j
	int j = mid + 1;    //mid+1是右边子数组的首元素下标
	int k = 0;  //作为数组B的下标
	while (i <= mid && j <= right)
	{
		if (arr[i] <= arr[j])  //较小者拎出来
		{
			B[k++] = arr[i++];  //注意是后缀自增,先赋值再自增
		}
		else   //这个就是右边的子数组的当前首元素较小的情况
		{
			B[k++] = arr[j++];
		}
	}  //当任意一个子数组走完了,不管另一个走没走完,这个循环都结束了
	while (i <= mid) //i还没到左边子数组的最右边,即还没走完,因为退出了循环,j所在的子数组肯定走完了,所以直接把i所在数组元素逐个添加就行
	{
		B[k++] = arr[i++];
	}
	while (j <= right)  //同理,这是右边子数组还没走完的情况
	{
		B[k++] = arr[j++];
	}
	for (int i = left, k = 0; i <= right; i++)
	{
		//因为B数组待会要释放掉,所以把B数组赋值给arr
		arr[i] = B[k++];
	}
	delete[]B;  //释放B数组空间
}
void MergeSort(int arr[], int left, int right)  //用来分解数组的
{
	if (left < right)  //left!=right说明子数组还不止一个元素,需要继续递归调用
	{
		int mid = (left + right) / 2;
		MergeSort(arr, left, mid);
		MergeSort(arr, mid + 1, right);
		Merge(arr, left, mid, right);
	}
}
int main()
{
	int arr[5] = { 5,1,8,3,9 };
	MergeSort(arr, 0, 4);    //数组作为形参时,传递的是地址。在函数中修改数组就相当于修改了原数组。
	for (int i = 0; i < 5; i++)
	{
		cout << arr[i] << ' ';
	}
	return 0;
}

输出: 1 3 5 8 9

举报

相关推荐

0 条评论