归并排序---天下大事,合久必分,分久必合
1. 思路
归并排序基于分治思想,即先把复杂的大问题分割成多个简单的小数据,然后逐个击破,从而达到解决问题的目的。他非常符合中国人的思维习惯:大事化小,小事化了。下面用一张图来描述这个过程:
蓝色为分解为分解过程,绿色为合并过程。
数组在分解过程中,几乎没有任何操作,所有的比较,交换操作都在合并过程中。我们在这里主要讨论一下合并的过程,这是归并算法的核心逻辑部分。我们之前已经了解了插入算法,并且知道插入算法的特性是数组的有序性越好,插入算法性能越高。对于两个有序的临近数组,用插入算法进行合并,应该也会得到相对不错的性能。我们知道插入算法的时间复杂度为O(N2)。在这里我们使用另一种思路,用空间换时间,使其合并的复杂度由O(N2)降低至O(N)。我们可以创建与原序列等长的数组,来描述一下这个过程:
1, 我们截取上图一部分作为开始,入下图
创建一个空数组
2,将需要合并的两个数组全部copy到新数组中
定义变量k指向合并后数组的第0位,i位第一个数组的起始位置,j为第二个数组的起始位置。然后比较[i] =0 与[j]=2的大小,将[i]赋值到[k]中,同时i增长1,k增长1,准备下一次计算
承上,继续比较[i] =1 与[j] =2的大小,将[i]赋值到[k]中,同时i增长1,k增长1,准备下一次计算
呈上,比较[i] =3与[j]=2的大小,将[j]赋值到[k]中,同时j增长1,k增长1,准备下一次计算
呈上,比较[i] =3与[j]=5的大小,将[i]赋值到[k]中,同时i增长1,k增长1,准备下一次计算
......
直到
一次合并完成。
2. 代码片段
① 归并排序堆外接口
② 归并排序递归函数
③ 合并核心逻辑
④ 执行过程
3.复杂度分析
实际上我们上面已经分析过了,对于递归算法,分的过程几乎忽略不计,核心处理在归并部分。对于任何数组N,合并的层数为logN,而每一层的时间复杂度通过开辟一块与原数组大小相等的空间达到了线性O(N)。所以综上时间复杂度为O(NlogN).空间复杂度O(N)。
4.思考
最后,递归排序给我们的提示有两个。一个是分治思想。对于比较庞大的复杂问题,分解成小的简单问题,有助于问题的解决。第二个提示是,时间不够,空间来凑。很多问题都是没有最优解的。往往需要我们自己在实际情况下在时间,空间上权衡,从而达到目标。