归并排序—递归&非递归

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dream_1996/article/details/78664466

归并排序


把数组平均分成两半,若两个区间有序后,则进行归并。使两个区间有序和快排同样的方法一样,递归到最后只有一个值或者没有时即有序。但在归并时需要开辟一段空间把合并的数据存起来,再放回原数组。

适合外部排序

可以实现外部排序,把两个有序的文件,依次读取出来归并到一个新的文件里。

注意

归并时选择选择两个数组头部小的一个时,要有等于号,否则两个头部相等时会发生死循环。

优化

  • 小区间优化

小区间优化在快排里有讲

时间复杂度

O(n*lgn)

代码实现

void MergeSort(int *a, int left, int right)
{
	if (left >= right)
		return;
	int mid = left + ((right - left) >> 1);

	MergeSort(a, left, mid);
	MergeSort(a, mid+1, right);

	//归并
	Merge(a, left, mid, right);

}

void Merge(int *a, int begin ,int mid,int end)
{
	int *tmp = new int[end - begin + 1];

	int begin1 = begin;
	int begin2 = mid+1;
	int end1 = mid;
	int end2 = end;

	int index = 0;
	while (begin1 <= end1&&begin2 <= end2)
	{
		while (begin1<=end1&&a[begin1] <= a[begin2])
		{
			tmp[index++] = a[begin1++];
		}
		while (begin2<=end2&&a[begin1]>=a[begin2])
		{
			tmp[index++] = a[begin2++];
		}
	}
	while (begin2 <= end2&&begin1 > end1)
	{
		tmp[index++] = a[begin2++];
	}
	while (begin1 <= end1&&begin2 > end2)
	{
		tmp[index++] = a[begin1++];
	}
	for (int i = begin, j = 0; i <= end; i++, j++)
	{
		a[i] = tmp[j];
	}
	delete[] tmp;
}

非递归

循环的非递归,先一一归并,然后再两两归并,直到最后一半与另一半归并。

代码实现

//[left,right]
void MergeSortNR(int *a, int left, int right)
{
	int begin = 0;
	int end = 0;
	int mid = 0;
	//gap是两个要和并分组其中一个的步长。
	for (int gap = 1;gap<=(right-left+1);gap*=2)
	{
		begin = left;
		while (1)
		{
			mid = begin + gap - 1;
			end = begin + 2 * gap - 1;

			//mid>right剩下的不足一个组,肯定已经有序,因为gap是从1增长的。
			if (mid>right)
			{
				break;
			}
			//中间值没有超,右边界超了,[begin,mid] [mid,right]
			if (end > right)
			{
				end = right;
			}
			MergeNR(a, begin, mid, mid + 1, end);
			begin = end + 1;
		}
	}
}
void MergeNR(int *a, int begin1, int end1,int begin2, int end2)
{
	int *tmp = new int[end2 - begin1 + 1];

	int left = begin1;
	int right = end2;
	int index = 0;
	while (begin1 <= end1&&begin2 <= end2)
	{
		while (begin1 <= end1&&a[begin1] <= a[begin2])
		{
			tmp[index++] = a[begin1++];
		}
		while (begin2 <= end2&&a[begin1] > a[begin2])
		{
			tmp[index++] = a[begin2++];
		}
	}
	while (begin2 <= end2&&begin1 > end1)
	{
		tmp[index++] = a[begin2++];
	}
	while (begin1 <= end1&&begin2 > end2)
	{
		tmp[index++] = a[begin1++];
	}
	for (int i = left, j = 0; i <= right; i++, j++)
	{
		a[i] = tmp[j];
	}
	delete[] tmp;
}
  • 空复复杂度高,需要开辟同等大小的空间
  • 但归并排序可以进行外部排序

猜你喜欢

转载自blog.csdn.net/dream_1996/article/details/78664466