排序算法总结

本文为原创,如需转载,请注明作者和出处,谢谢!

最近因为找实习的缘故,开始苦心研究算法了。这次就总结下排序算法吧。

最简单的就是插入排序和冒泡排序,插入排序就是将第n个数插入到前n-1个有序的子列中,不断循环完成排序;冒泡排序不断地两两比较,把大的数往后移动,类似于一个网上蹿的气泡一样。冒泡排序时间复杂度是o(n2),插入排序因为可以用折半查找的方式,所以时间复杂度为O(nlogn),这两种算法的空间复杂度都为O(1)。快速排序对于小数据量时性能优秀,冒泡排序可以加入一个标志flag,如果某一轮比较没有移动,那么就可以结束算法,对算法的时间复杂度有线性的优化。

稍微复杂点的算法有堆排序算法,归并算法,快速排序3种,它们的时间复杂度都是O(nlogn),这三种也是面试常考的。先说我最喜欢的堆排序吧,这种排序方式需要用到堆这种数据结构。所谓堆就是一棵完全二叉树,它的任意父节点总是大于该父节点的任意子节点,所以堆的根节点就是最大的节点(当然也有最小堆,最小堆的根节点就是最小的节点)。该算法的核心思想就是不断地取根节点,然后恢复堆,完成排序。从一个无序的数组建堆的时间复杂度是O(n),恢复堆的时间复杂度为O(logn),所以总共的时间复杂度就是O(n + nlogn)也就是O(nlogn)。这种排序算法时间复杂度比较稳定,不依赖输入数组的情况,空间复杂度也令人满意,另外这种排序算法还可以用来找第k大的数,例如总共有1000个数,让你找第7大的数,方法就是用前7个数建立一个大小为7的最小堆,然后所有剩余元素依次做如下操作:将下一个元素与堆顶比较,如果小于堆顶,那么继续下一个;如果大于堆顶,就删除堆顶,再恢复堆。直到所有元素都插入后,堆顶的元素就是第7大的数,这样做得时间复杂度是O(nlog(k)),也就即O(n)。

归并排序的思想是将两个有序的子列合成一个完成排序,实际操作就是递归地把数组分成两段,直到某一个子列由两个长度为1的子列组成,这两个子列必然是有序的,这时开始合并子列。合并的方式用两个指针指向两个子列的头,然后比较,小的元素移动到一块新开辟的内存中,这样一次的时间复杂度是O(n),总共进行logn次,所以时间复杂度是O(nlogn),空间复杂度为O(n)。该算法的缺陷就是需要额外的存储空间,为了节省额外的存储空间,所以就有了快速排序。

快速排序的思想是选定一个支点将原数组分为两个子列,其中左边的子列都小于该支点,右边的子列都大于该支点,然后对子列也进行这样的操作,最终就对数组完成排序了,支点的选择一般可以考虑第一个元素,或者是随机选择某个元素,最理想的情况是每次选择的支点都是数组的中值,那么这样的话时间复杂度就是O(nlogn)。但也有可能是最坏的情况也就是每次选择的支点都是最大或者最小的数,那么时间复杂度就是O(n2),所以在优化上考虑将数组打乱或者是扫一遍数组看数组是否有序,这样可以避免最坏的情况。

另外还有几种线性时间的排序算法,但都对输入数组有要求,例如桶排序,要求输入数组必须是均匀分布的,例如n个整数排序,大小分别为1...n,那么只用扫描一遍数组就可以完成排序。其思想是将[1,n]划分成n个子区间,或者是桶,然后将n个输入数分布到各自各个桶中,只要把每个数据放到对应的桶中就可以完成排序。例如一个Int数组第一个数是5,那么就放到第5个桶,即a[4]中。

posted @ 2011-06-11 14:01  影の心  阅读(257)  评论(0编辑  收藏  举报