归并排序(分治策略)

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

	        private var arrTest:Array=[9, 8, 7, 6, 5, 4, 3, 11, 21, 12, 2, 1, 0, 63];
		/** 辅助数组,避免频繁new数组开辟内存空间以及传递不必要的数组,这里直接在外面new一次,归并排序时直接调用 */
		private var temp:Array=[];

		/**
		 * 将两个有序数组arr[left...mid]和arr[mid...right]合并
		 * @param arr
		 * @param left
		 * @param mid
		 * @param right
		 * 总的时间复杂度为O(n)
		 */
		private function mergerArr(arr:Array, left:int, mid:int, right:int):void
		{
			var i:int=left;
			var j:int=mid + 1;
			var m:int=mid;
			var n:int=right;
			var k:int=0;
			//此处while时间复杂度为O(n)
			while (i <= m && j <= n)
			{
				if (arr[i] <= arr[j])
				{
					temp[k]=arr[i];
					i++;
					//temp[k++] = arr[i++];
				}
				else
				{
					temp[k]=arr[j];
					j++;
					//temp[k++] = arr[j++];
				}
				k++;
			}
			//某一个子数组扫描完了,另一个子数组还有元素没有被扫描过,则直接往新数组末尾插入
			while (i <= mid)
			{
				temp[k]=arr[i];
				k++;
				i++;
			}
			while (j <= n)
			{
				temp[k]=arr[j];
				k++;
				j++;
			}
			//时间复杂度为O(n)
			var a:Array=[];
			for (var l:int=0; l < k; l++)
			{
				arr[left + l]=temp[l];
				a.push(temp[l]);
			}
			console.log("--------" + a.join(',') + "--------");
		}

		/**
		 * 将无序数组arr递归拆分成有序子数组(数组长度为1时视为有序)
		 * @param arr
		 * @param left
		 * @param right
		 *
		 */
		private function mergerSort(arr:Array, left:int, right:int):void
		{
			if (left < right)
			{
				var mid:int=Math.floor((left + right) / 2);
				//使左边有序
				mergerSort(arr, left, mid);
				console.log();
				//使右边有序
				mergerSort(arr, mid + 1, right);
				//将左右两边的有序子数组合并
				mergerArr(arr, left, mid, right);
				var arrLeft:Array=[];
				var arrRight:Array=[];
				for (var i:int=left; i <= right; i++)
				{
					if (i <= mid)
					{
						arrLeft.push(arr[i]);
					}
					else
					{
						arrRight.push(arr[i]);
					}
				}
				console.log("合并了子数组[" + arrLeft.join(',') + "]和[" + arrRight.join(',') + "]");
			}
		}

通过添加打印信息可以看到归并排序的内部排序过程

先将无序数组拆分成长度为1的数组,此时视为有序,然后对左边子数组递归调用归并排序,再对右边子数组递归调用归并排序,最后对左右两个子数组调用归并排序。

归并排序每次将子数组一分为二,直至子数组长度为1或者0,需要拆分的次数为\log_{2} n,每次合并子数组的时间复杂度为O(n),所以归并排序总的时间复杂度为O(nlgn),且最好最坏平均时间复杂度都为O(nlgn)。

考虑到归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(nlgn)的几种排序方法中(快速排序,归并排序,希尔排序,堆排序)相对而言,效率较高。

分治思想常用于海量数据处理,例如,计算机内存只有1G,但是现在需要对2G的数据进行排序,无法一次性将所有数据加载到内存,这时候就可以采用分治策略,将数据根据某种方法拆分为小的数组集合(小于计算机内存),对各部分数据集合单独加载到计算机内存排序,各部分排完序之后,再将各部分数据集合合并成大的数据集合。

发布了61 篇原创文章 · 获赞 2 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_22794043/article/details/89950694