归并排序(merge-sort),是一种时间复杂度为O(nlog n),空间复杂度为T(n)的排序算法,发明者为大名鼎鼎的20世纪的全能通才——约翰·冯·诺依曼。
我们先来看看O(nlog n)和O(n^2)的时间复杂度的比较:
差距一目了然。。。不用说了吧。
然后我们来看一下归并排序算法:我们想把下图中的元素从小大到排序,使用归并排序算法的思想怎么做呢?
是这样的,归并算法的思想是:我们可以把上面的元素分成两半,两半排好序,再把它们归并。
上面这个图,我们是怎么让左边的一半和右边的一半都拍好序的呢?其实我们的思想也是又继续对半的分
先将左右两边的那组
元素分成一半的一半,然后再分成一半的一半,然后再分成一半一半.......就像下图这样的分,直到分到只有一个元素的时候,这时候就不能再分了。
这时候,可以把只有一个元素的部分看成已经排好序,然后依次归并回去。
下面我们来看:
上图有8个元素,分到不能再分,最底层是第3层(从0开始),找规律可得其实就是8/2,8/2/2,8/2/2/2,也就是log以2为底8的对数层,那么有N个元素,就是log(N)层
总之,当元素有N个的时候,这个层数就是log(N)这样的数量级的,在这种情况下,我们要处理的数量级都是一样的N,虽然我们把它分成了不同的部分。
到上面这里,我们又怎么让左右两边的元素归并呢?看着虽然简单,但是代码不简单啊。。。。天才的世界就是不一样。
我们不能再像冒泡排序、插入排序,选择排序那样的判断交换位置了,而是需要开辟一个新的一毛一样和原来的数组元素一样大的空间来辅助我们完成归并排序。
使用了临时空间,归并的过程将变得非常容易。。。。(( ╯□╰ ))
然后,我们需要使用3个索引,用于指向不同的位置
我们左边和右边的两个索引对应的元素比较大小,小的放入临时空间中,同时,移动指针
重复上面的过程就可以完成了归并排序
下面是Java代码的实现(主要代码):
merge(arr,l,mid,r)归并方法:
当我们的元素像上图这样的话,可能左边已经归并好,右边还没有好,防止索引越界之后一序列问题,这时候我们就需要判断了
同理,也有可能右边已经归并好了,左边的没有好
时间复杂度分析,一共有log(N)层,每层的元素都一样都是N,我们在归并过程中,每层都归并N次,也就是时间复杂度为O(nlog n),空间复杂度为T(n)
以后再补充吧,有的地方还是不太懂,慢慢来咯,比如优化方面,还有其他的( ╯□╰ )