现实中人的排序有时比机器排序快,原因是人有快速判断当前情况适用于什么排序的经验。比如近乎有序的书架不需要过多不必要的对比,尽管对比成本较低,所以我们依赖冒泡,而不用插入,不用从开始对比到结尾,我们知道前面的都是有序的,而无序的两本书相互间距是很小很小的。
首先要记住一个很重要的排序速度分析结果:
快速排序(合并排序) > 插入排序 > 选择排序 > 冒泡排序
quick sort > insertion sort > selection sort > bubble sort
在《algorithms to live by》书中是这样描述冒泡排序的:
你在书架前巡视,看到两本书颠倒了先后次序,就把他们调换过来。走到书架尾端时,再回过头来从书架最前端重新开始。
冒泡排序在有逆序时进行交换,目的是达成有序。操作多而比较少,冒泡稳定在它的"操作前付出"比较少,所以正误不会差距太大。
而插入排序:
把所有书从书架上拿下来,然后一本一本放在合适的位置。把第一本放在书架中间,然后拿第二本和第一本比较,根据比较结果把它插到第一本的右边或左边。放第三本书时,从左往右浏览书架,把它放到合适的位置。然后你不断重复这个过程。
插入不在乎后面的是否有序,只要自己现今有序即可,越到后面要移动的位数越多。(简单的后果是越来越复杂)
则选择排序可以这样说:
你在书架前巡视,走到书架尾端时,你找到了在这一趟中序号最小的书。然后你将序号最小的书放在最前面,并从书架最前端重新开始。
选择只考虑在一堆书中找出最小。所以其比较最多,操作最少。
选择侧重比较,冒泡则不断通过交换趋向有序状态。
由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。当书架上的书比较少的时候(假定书是完全无序的),选择排序比冒泡排序速度更快。
插入比选择更快。(这不是明摆着的吗!!!)选择有较多比较,相比插入来说,选择的冗余过多。插入在情况比较好时可以迅速插值,而选择就很尴尬了,每次都要进行全对比。
所以人类之所以不用冒泡排序(处理完全无序数列)的原因果然是两本书交换来交换去太累了。
在已比较有序的情况下,我们无需大量的重复比较运算,因而,在处理比较有序书籍问题时,冒泡排序比选择排序更为合理有效。
插入排序是将一本书放入书架中间,从左到右浏览书架放置于合适位置。插入排序在实践中比冒泡更快,因为冒泡排序是无法解决完全无序的问题的。
这些算法都要进入平方时间。
《algorithms to live by》书中给出了解决平方时间的排序方法:分治算法。
如果排序有O(n)算法,那便只有一个维度上的排序,但这是不可能的,因为第n的排序一定要和m个进行比较得到,这和无需比较的排序有所不同。所以计算机科学家把排序复杂度简化目标定在了n和n2所构成的函数空间内。
于是有了复杂度为O(n log n)的线性对数复杂度排序算法————分治算法。算法中最璀璨的分而治之在排序中也焕发了不朽的光芒。现在被称为合并排序,计算机有时会用快速排序。
所以书架上的书有了新的分类方法:
把书平均分配,并让每个负责整理其中一堆。接着,让朋友们两两配对,把他们负责的书合并在一起。重复这个过程,直到最后剩下两堆书,再一次性地合并到书架上。需要注意的是,不要让比萨弄脏了那些书。
分而治之时,自己选的分治算法合并时要避免错误。
现实中人的排序有时比机器排序快,原因是人有快速判断当前情况适用于什么排序的经验。比如近乎有序的书架不需要过多不必要的对比,尽管对比成本较低,所以我们依赖冒泡,而不用插入,不用从开始对比到结尾,我们知道前面的都是有序的,而无序的两本书相互间距是很小很小的。
很多西方学者建议从教科书中取消冒泡排序。因为除了在满足两个条件下:
- 数据(书架)已大致有序
- 两个无序数据(书架)离的很近
我们难以理解冒泡排序的一个原因就是因为它对我们来说太常见太简单了,以致于无法去思考其算法,因为压根感觉不出来。
然后有了超越比较法。