排序算法之归并排序

左心房为你撑大大i 提交于 2019-11-26 17:54:43
归并排序
基本思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。利用将已有序的子序列合并,得到完全有序的序列进行排序;即先使每个子序列有序,再使子序列段间有序。然后继续进行归并直到最后整个序列有序。

排序过程

算法首先将待排序序列均分为两部分,然后对于每部分继续均分下去,直到划分为不可分割的一个元素为止;然后按照分割的逆向进行归并,归并两个分组时,依次比较两个分组内的元素的大小,以此来进行排序操作,当一次归并排序完成后,继续和其他的分组以相同的方式进行归并,直到归并为一整个待排序序列,此时整个序列便已经有序,算法结束。
在这里插入图片描述

C语言代码实现

递归方式实现:

// 升序排序
void _MergeSort(int* a, int left, int right, int* tmp)
{
	if (left == right)
		return;

	int mid = left + (right - left) / 2;
	// [left, mid] [mid + 1, right] 分别有序
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);

	// [left, mid] [mid + 1, right] 归并到tmp[left, right]
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int i = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[i++] = a[begin1];
			++begin1;
		}
		else
		{
			tmp[i++] = a[begin2];
			++begin2;
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1];
		++begin1;
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2];
		++begin2;
	}

	memcpy(a + left, tmp + left, sizeof(int)*(i - left));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
}

非递归方式实现(利用循环):

// 升序排序
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);

	int gap = 1;
	while (gap < n)
	{
		// [begin, end]
		for (int begin = 0; begin < n; begin += 2 * gap)
		{
			// [begin, begin+gap-1] [begin+gap, begin+2*gap-1]
			int begin1 = begin, end1 = begin + gap - 1;
			if (end1 >= n)
				end1 = n - 1;

			int begin2 = begin + gap, end2 = begin + 2 * gap - 1;
			if (end2 >= n)
				end2 = n - 1;

			int index = begin1;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] <= a[begin2])
					tmp[index++] = a[begin1++];
				else
					tmp[index++] = a[begin2++];
			}

			while (begin1 <= end1)
				tmp[index++] = a[begin1++];
			while (begin2 <= end2)
				tmp[index++] = a[begin2++];
		}
		memcpy(a, tmp, sizeof(int)*n);

		gap *= 2;
	}
	free(tmp);
}
时间复杂度

归并排序同样利用递归算法的时间复杂度计算方法进行计算,归并排序的过程是先二分分解直到为单独的元素,然后进行归并,此时的递归树是一颗二叉树,这棵树的总节点数为待排序的元素个数N,所以归并排序的时间复杂度为O(N*logN)。

空间复杂度

由于进行归并时消耗了和原序列一样大小的空间用于临时存储,所以归并算法的空间复杂度为O(N)。

稳定性

归并排序是把序列划分成短序列,然后把各个有序的短序列合并成一个有序的长序列,不断合并直到原序列全部有序。在序列最小时1个元素,或2个元素时,1个元素不发生交换,2个元素如果大小相等不进行故意交换,这样就不会破坏稳定性。在之后的合并过程中可以保证如果两个当前元素相等时,把处在前面的序列的元素保存在结果序列的前面,所以,归并排序是稳定的。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!