递归方法实现:

//用递归的方法实现归并排序
void mergeSort1(int arr[],int length)
{
	if (length < 2)
	{
		return;
	}
	process(arr, 0, length - 1);
}
//递归分组及归并
void process(int arr[], int L, int R)
{
	//L=R说明只有一个元素,不用分组了
	if (L == R)  
	{
		return;
	}
	int mid = L + ((R - L) >> 1);
	//将数组分为左右两边,排序与归并
	process(arr, L, mid);
	process(arr, mid + 1, R);
	merge(arr, L, mid, R);
}
//归并函数
void merge(int arr[], int L, int M, int R)
{
	int* help = new int[R - L + 1];
	int i = 0;
	int p1 = L;
	int p2 = M + 1;
	while (p1 <= M && p2 <= R)
	{
    //左边的数小于等于右边时拷贝,即优先拷贝左边,起到稳定排序的作用
		help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];

	}
	while (p1 <= M)
	{
		help[i++] = arr[p1++];
	}
	while (p2 <= M)
	{
		help[i++] = arr[p2++];
	}
	for (i = 0; i < R - L + 1; i++)
	{
		arr[L + i] = help[i];
	}
}

非递归方法实现:

//非递归方法实现归并排序
void mergeSort2(int arr[], int length)
{
	//数组只有一个元素时,不用排序
	if (length < 2)
	{
		return;
	}
	int mergeSize = 1; //当前需要归并的数组左边元素个数
	while (mergeSize < length)
	{
		int left = 0;
		while (left< length)
		{
			//mid是左边分组的末尾元素坐标,一共mergeSize个元素,其坐标当然要-1
			int mid = left + mergeSize - 1;
			if (mid >= length)
			{
				break;
			}
			//right是右边分组的末尾元素坐标
			int right = (mid + mergeSize) < (length - 1) ? (mid + mergeSize) : length - 1;
			//归并当前组的元素
			merge(arr, left, mid, right);
			//开始下一组的归并
			left = right + 1;
		}
		//经过以上循环,原数组被分成[length*1.0/(2*mergeSize)]组,这里[]意为向上取整,并且每组都经过归并
		//这里if语句防止length过大时,mergeSize溢出
		if (mergeSize > length / 2)
		{
			break;
		}
		mergeSize <<= 1;
	}
}

归并排序的时间复杂度:N*logN。

常见题目:

(1)在一个数组中,一个数左边比它小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。求数组小和。