各种常见排序算法的思路(比较)
以前搞过1年的ACM,听别人说算法很重要,可是自己没怎么把它放在心上,今天开始找工作了,终于体会到了算法的重要性,下面是我对各种常用内部排序算法的一点总结。
排序算法的比较:
排序算法 | 平均时间 | 最坏时间 | 辅存空间 | 稳定性 | 备注 |
直接插入 | O(n2) | O(n2) | O(1) | 稳定 | 大部分已排序时较好,最少n-1次 |
冒泡 | O(n2) | O(n2) | O(1) | 稳定 | n小时较好,最少比较n-1次 |
选择 | O(n2) | O(n2) | O(1) | 不稳定 | n小时较好 |
快速 | O(nlogn) | O(n2) | O(logn) | 不稳定 | n大时最快的排序 |
希尔 | O(nlogn) | O(ns) | O(1) | 不稳定 | s是所选分组 |
堆排序 | O(nlogn) | O(nlogn) | O(1) | 不稳定 | 适合大量数据 |
归并排序 | O(nlogn) | O(nlogn) | O(n) | 稳定 | n大时较好 |
基数排序 | O(d(n+r)) | O(d(n+r)) | O(rd) | 稳定 | d为关键字位数,r为基数 |
各排序算法原理:(默认从小到大排序)
1 直接插入排序(InsertSort)
直接插入排序是一种最简单的排序方法,通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。即先将第1个记录看作是一个有序的记录序列,然后从第2个记录开始,依次将未排序的记录插入到这个有序的记录序列中去,直到整个文件中的全部记录排序完毕。
2 冒泡排序(BubbleSort)
冒泡排序算法也是一种非常简单的排序算法,第一趟排序:n个数中,K1开始,依次比较两个相邻的关键字Ki和Ki+1(i=1,2,…,n-1),若Ki>Ki+1,则交换相应记录Ri和Ri+1的位置, 否则,不进行交换。经过这样一遍处理后,其中关键字最大的记录移到了第n个位置上。第二趟排序:对前面的n-1个记录进行第2遍排序,重复上述处理过程,第2遍之后,前n-1个记录中关键字最大的记录移到了第n-1个位置上,继续进行下去,直到不需要再交换记录为止。(最少比较次数为n-1是因为设置了change变量)
3 选择排序(SelectSort)
选择排序与冒泡排序非常相似,第一趟排序:从n个数中选择最小的1个放在第一个位置,第二趟:从剩下的n-1个数中选择一个最小的数放在第2个位置,依次类推。冒泡排序是比较相邻的交换相邻的,而选择排序不是。
4 希尔排序(Shell)
希尔排序属于插入类排序,是将整个无序序列分割成若干小的子序列分别进行插入排序。排序过程:先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;然后取d2<d1(其中d2=(d1+1)/2 eg:D可以选取{9,5,3,2,1}。),重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止。
5 快速排序(QuickSort)
通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。一遍快速排序算法的做法:
方法1、附设两个指针Low和High,它们的初值分别为low和high,设枢轴记录的关键字为pivotkey。从high所指位置起向前搜索到第1个关键字小于pivotkey的记录和枢轴记录互相交换;从low所指位置起向后搜索,找到第1个关键字大于pivotkey的记录和枢轴记录互相交换;重复这两个操作直至low=high为止。
方法2、i=low,扫描i后元素,i后位置一有比主元pivotkey小的元素,i就后移并交换i位置的元素和正在扫描的元素,最后i位置就是一个正确的位置。
6 堆排序(HeapSort)
堆排序适合于数据量非常大的场合(百万数据)。初始化创建大顶堆,然后循环执行以下过程,直至数组为空为止:把堆顶元素和当前堆的最后一个元素进行交换;最大堆元素个数减1,调整新堆根节点使之满足最大堆的定义。最终整个堆变为有序的最小堆。
7 归并排序(MergeSort)
归并排序先分解要排序的序列,从1分成2,2分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个等容量的额外的数组。
思路:一个有序的数组是有两个有序的数组合并成的。
8 基数排序
基数排序和通常的排序算法并不走同样的路线。它是一种比较新颖的算法,但是它只能用于整数的排序,如果我们要把同样的办法运用到浮点数上,我们必须了解浮点数的存储格式,并通过特殊的方式将浮点数映射到整数上,然后再映射回去,这是非常麻烦的事情,因此,它的使用同样也不多。而且,最重要的是,这样算法也需要较多的存储空间。
思路:先按个位将各个数依次排在0-9个桶(队列)中,然后收集起来,再按照十位将他们重新分配到这十个桶中,再收回,依次类推。