【数据结构】八大排序之归并排序

一.归并排序的基本思想

          归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

如下图:

1.我们看到在分治的方法中其中重要的一步就是合并两个有序数组,接下来我们先看一下如何将两个有序数组合并在一起:

思路:开辟一段辅助空间(空间大小是两个有序数组的大小之和)然后一次比较两个有序数组中的数,哪个数组中的数比较小,就将该数组中的数放到开辟的辅助空间中。

代码如下:

int add(int arr1[], int sz1, int arr2[], int sz2, int arr3[])
{
	int i = 0;
	int j = 0;
	int n = 0;
	while (i < sz1 && j < sz2)
	{
		if (arr1[i] < arr2[j])
		{
			arr3[n++] = arr1[i++];
\
		}
		else
		{
			arr3[n++] = arr2[j++];
		}
	}
		while (i < sz1 )
		{
			arr3[n++] = arr1[i++];
		}
		while (j < sz2)
		{
			arr3[n++] = arr1[j++];
		}
	
}

              可以看出合并两个数组的效率是非常高的,为O(n)

2.解决了合并的问题,接下来我们只要将数组中分为两个有序数组(A数组,B数组),那么一切都会解决,这里我们用递归的方法,将原数组从中间分为两个数组,然后将分开的两个数进行排序。

排序的思路:

可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。

代码如下:

void mergesort(int arr[], int left, int right, int arr1[])
{
	int mid = (left + right) >> 1;
	if (left < right)
	{
		//左边有序
		mergesort(arr, left, mid, arr1);
		//右边有序
		mergesort(arr, mid + 1, right, arr1);
		//合并
		mergearray(arr, left, right, mid, arr1);
	}


}


//合并两个有序数组
void mergearray(int arr[], int left, int mid, int right, int arr1[])
{
	int first = left;
	int last = right;
	int first1 = mid + 1;
	int i = 0;
	while (first < mid && first1 < right)
	{
		if (arr[first] < arr[first1])
			arr1[i++] = arr[first++];
		else
			arr1[i++] = arr1[first1++];
	}
	while (first1 < right)
		arr1[i++] = arr[first1++];
	while (first < mid)
		arr1[i++] = arr[first++];

	for (int i = 0; i < right; i++)
		arr[i] = arr1[i];

}

//将数组分为两个有序数组
void MergeSort(int arr[], int sz)
{
	int* arr1 = (int)malloc(sizeof(int)*sz);
	if (arr == NULL)
		return NULL;
	mergesort(arr, 0, sz - 1, arr1);
	free(arr1);
}

归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。 

总结:

归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。(面试会问到)

猜你喜欢

转载自blog.csdn.net/alidada_blog/article/details/82797648