从代码上实现上看,这个排序算法看似很牛逼的样子,分治思想、递归实现都用上了。我们想要排序下标是i到j之间的数据,算法先排序好前半段,再排序好后半段,然后把最大值放到下标为j的位置,最后还要再把除了最大值之外的下标是i到j之前的数据,再重新排序。
算法是正确,可以实现将一个无序数据集合排序的效果。但如果我们把时间复杂计算的递归公式写出来,你就知道,它的时间复杂度很高了。
T(n) = 2*T(n/2) + T(n-1) + C(C表示常量时间)
这个时间复杂度的公式推导很复杂,我直接给出结论: ,并不是一个多项式时间复杂度的算法,也就是说,是一个无效的算法。
4. 侏儒排序算法(Stupid Sort)
Stupid排序算法,起初由 Hamid Sarbazi-Azad 于 2000 年提出,后来被 Dick Grune 命名为 “Gnome排序” 。从名字上就可以看出,它也并不是一个很高明的排序算法。这个算法是如何工作的呢?我们先看它的伪代码实现,稍后再解释。
procedure gnomeSort(a[]):
pos := 0
while pos = a[pos-1]):
pos := pos + 1
else:
swap a[pos] and a[pos-1]
pos := pos - 1
这个算法的思想非常贴合我们平时生活中整理东西的逻辑。假设我们站在pos这个下标位置上,0到pos-1这pos个数据已经是从小到大排好序的了。如果pos-1这个位置的数据小于等于pos,那我们前进一位(pos++);相反,如果pos-1这个位置的数据大于pos这个位置的数据,我们就将两个数交换,并且后退一步(pos--),继续跟已经排好序的数据比较。
实际上,从上面的工作原理的分析来看,这个算法有点类似冒泡排序。而且,尽管名字叫Stupid算啊,实际上,性能并不是太差,最坏情况是时间复杂度是O(n^3)。
5. 臭皮匠排序算法(Stooge Sort)
Stooge排序算法,从实现上来看,有点类似于Stupid算法。不过,它比Stupid算法的性能稍强点,时间复杂度是O(nlog 3 / log 1.5 ) = O(n2.7095...)。
Stooge排序算法是怎么工作的呢?我们先来看下它的伪代码实现。
function stoogesort(array L, i = 0, j = length(L)-1) {
if L[i] > L[j] then
swap L[i], L[j]
if (j - i + 1) > 2 then
t = (j - i + 1) / 3
stoogesort(L, i , j-t)
stoogesort(L, i+t, j)
stoogesort(L, i , j-t)
return L
}
从代码实现上来看,这个算法非常规整、非常优美。我稍微解释一下。
如果最后一个元素小于第一个元素,我们交换两个数。如果当前集合元素数量大于等于3,那先递归排序前2/3的元素,再递归排序后2/3的元素,最后再递归排序一次前2/3的元素。
实现原理很巧妙哈,我们来看下,算法结束之后,是否能产生排好序的数组呢?
实际上,这个算法的正确性证明很简单。我们把整个数组分成三段,每段占1/3。前1/3段我们记作A,中间1/3段我们记作B,后面1/3段我们记作C。
经过第一轮排序之后,[AB]已经有序了,也就说,B中的数据肯定大于A中的数据。经过第二轮排序之后,[BC]就有序了,也就说C中数据肯定大于[AB]中的数据,也就是说,C中的数据肯定是这个数组中最大的1/3数据了。
那这个时候,[AB]种的数据是否仍然有序呢?经过第二轮排序之后,[AB]中的数据变得无序了,所以我们需要再进行一轮排序,也就是代码中的最后一次排序。听起来是不是有点类似汉诺塔算法呢?
今天,我只是给你展示了这些奇葩的排序算法,如果你对哪个感兴趣,可以自己去更深入的研究下。除此之外,你还知道其他哪些脑洞大开的排序算法呢?欢迎留言区说说。
关注我的微信公众号:小争哥,获取更多、更新的技术、非技术分享。
作者:前Google工程师,5万人订阅《数据结构和算法之美》专栏作者。
希望通过我加速你的技术、职场进步。