归并排序来袭

归并排序的基本思想是将两个或两个以上的有序表组合成一个新的有序表。来张丑图:

归并排序来袭_第1张图片

来上代码:

//归并排序递归
void Merge(int *arr, int start, int mid, int end)
{
	assert(NULL != arr);
	int low = start;
	int high = mid + 1;
	int *brr = (int *)malloc(sizeof(int)*(end - start + 1));
	int i = 0;
	while (low <= mid && high <= end)
	{
		if (arr[low] < arr[high])
		{
			brr[i++] = arr[low++];
		}
		else
		{
			brr[i++] = arr[high++];
		}
	}
	while (low <= mid)
	{
		brr[i++] = arr[low++];
	}
	while (high <= end)
	{
		brr[i++] = arr[high++];
	}

	for (int k = 0; k 

是不是感觉递归那块有点迷糊,来看下面这这张丑图:

归并排序来袭_第2张图片

 是不是感觉清晰点了,讲真,不懂多画图,没毛病!!

以上是归并排序的递归实现,那么如何将递归变为非递归呢?发现递归主要是一层一层进去,等到合并的两个有序表为1的时候才开始合并,那么我们是不是可以直接控制这两个有序表的大小,没错,当然可以,看代码:

//归并排序非递归
void meger(int *arr, int len, int gap)
{
	int *brr = (int *)malloc(sizeof(int)* len);
	assert(brr != NULL);

	int i = 0;
    //初始化要合并的区间,2路归并
	int L1 = 0;
	int H1 = L1 + gap - 1;

	int L2 = H1 + 1;
	int H2 = L2 + gap - 1 <= len - 1 ? L2 + gap - 1 : len - 1;

	while (L2 <= len - 1)
	{
		while (L1 <= H1 && L2 <= H2)
		{
			if (arr[L1] <= arr[L2])
			{
				brr[i++] = arr[L1++];
			}
			else
			{
				brr[i++] = arr[L2++];
			}
		}

		while (L1 <= H1)
		{
			brr[i++] = arr[L1++];
		}
		while (L2 <= H2)
		{
			brr[i++] = arr[L2++];
		}
        //让区间后移,继续进行合并
		L1 = H2 + 1;
		H1 = L1 + gap - 1;
		L2 = H1 + 1;
		H2 = L2 + gap - 1 < len - 1 ? L2 + gap - 1 : len - 1;
	}

	while (L1

程序中用for循环直接控制了要归并的序列的区间大小,即1,2,4,8,16

是不是感觉也非常的清晰,代码中的L1,H1,L2,H2是自己定义的要归并的序列的区间值。

来说下归并排序的复杂度:

递归

一趟归并需要将待排序序列中的所有记录扫描一遍,耗费O(n),整个归并排序需要进行(log2N,以2为底N的对数向上取整)次,所以总的时间复杂度是O(n*logn)。  

空间复杂度是O(n+logn)包括栈空间。

非递归:

避免了栈空间的消耗,避免递归也减少了时间时间开销。建立归并使用非递归。

归并排序是两两比较,不存在跳跃,所以是稳定的一种排序。

 

你可能感兴趣的:(算法)