C语言实现归并排序

归并排序

  • 一、递归实现归并排序
  • 二、非递归实现归并排序
  • 四、归并排序的时间复杂度及稳定性

一、递归实现归并排序

C语言实现归并排序_第1张图片
用递归实现归并排序的思路就是把序列分成不可再分的子序列,合并两个有序的子序列,然后回溯(回溯就是递归结束返回上一层),再合并两个有序的子序列,再回溯再合并……
C语言实现归并排序_第2张图片

合并两个有序数列的思路是分成左区间和右区间,a[begin1]和a[begin2]比较,如果a[begin1]比a[begin2]小,就把它放入tmp,然后++begin1,反之亦然……最后如果左区间取完了就把剩余右区间全部放入tmp,反之亦然。

代码如下:

void _MergeSort(int* a, int left, int right,int*tmp)
{
	if (left >= right)
	{
		return;
	}
	int midindex = (left + right) / 2;
	_MergeSort(a, left, midindex,tmp);//归并左区间
	_MergeSort(a, midindex+1, right,tmp);//归并右区间
	int begin1 = left, end1 = midindex;//[left,midindex]
	int begin2 = midindex+1, end2 = right;//[minindex+1,right]
	int index = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		//把两个区间中小的放入tmp,然后++,当其中一个取空了就直接把另一个放入tmp
		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++];
	}
	for (int i =left ; i <=right  ; i++)//拷贝回原数组
	{
		a[i] = tmp[i];
	}
}
void MergeSort(int*a,int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);
	_MergeSort(a, 0, n-1,tmp);
	free(tmp);
}

void TestMergeSort()
{
	int a[] = { 6,1,2,7,9,3,4,5,10 ,8};
	MergeSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

二、非递归实现归并排序

C语言实现归并排序_第3张图片
非递归实现归并排序的思路就是定义一个区间间隔(gap),然后合并两个有序区间,然后gap=gap*2,再合并……如上图第一次排序时gap=1,就把7,5当成两个间隔为1的有序区间进行合并;第二次排序时gap=2,就把5 7,1 3当成两个有序区间合并;第三次排序:gap=4,就把1 3 5 7,2 4 6 8当成两个有序区间合并……
另外在合并时我们要注意边界的情况,注意是否有越界或者只有一个区间的情况发生。当只有一个区间时不用合并直接放入下一次排序就好;当越界时,我们要重新修订边界。如下:
C语言实现归并排序_第4张图片
C语言实现归并排序_第5张图片
代码中:if (begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
就是对这两种问题的修订

代码如下:

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	int gap = 1;
	while (gap<n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i+gap-1;//[i,i+gap-1]
			int begin2 = gap + i, end2 =i+2*gap-1 ;//[i+gap,a+2*gap-1]
			if (begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			int index = i;
			while (begin1 <= end1 && begin2 <= end2)
			{
				//把两个区间中小的放入tmp,然后++,当其中一个取空了就直接把另一个放入tmp
				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++];
			}
			for (int j = 0; j <=end2; j++)//拷贝回原数组
			{
				a[j] = tmp[j];
			}
		}
		
		gap *= 2;
	}
	
	free(tmp);
}
void TestMergeSortNonR()
{
	int a[] = { 6,1,2,7,9,3,4,5,10,8};
	MergeSortNonR(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

四、归并排序的时间复杂度及稳定性

归并排序的时间复杂度为O(N*logN),空间复杂度为O(N),具有稳定性

你可能感兴趣的:(c语言,算法,排序算法)