十大排序算法
十大排序算法
重言十大排序算法
冒泡排序 (Bubble Sort)
冒泡排序是一种简单的排序算法
它重复地遍历要排序的数列,一次比较两个元素,如果顺序错误就把它们交换过来
遍历的最终结果是会把最大的数冒泡地沉到最底下,最小的数会像鱼泡一样被冒泡地推到最上面来
算法步骤
比较相邻的元素。如果第一个比第二个大,就交换它们两个
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数
针对所有的元素重复以上的步骤,除了最后一个
重复步骤 1~3,直到排序完成
图解算法
实现代码
1 | /** |
算法分析
- 稳定性: 稳定
- 时间复杂度: 最佳: O(n) ,最差: O(n2), 平均: O(n2)
- 空间复杂度: O(1)
- 排序方式: In-place
选择排序 (Selection Sort)
选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度
所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧
它的工作原理: 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕
算法步骤
- 找到数组中最小的元素,和第一个元素交换位置
- 在剩余的元素中找到最小的元素,和第二个元素交换位置
- 重复步骤2,直到找到数组的最后一个元素
算法图解
代码实现
1 | /** |
算法分析
- 稳定性: 不稳定
- 时间复杂度: 最佳: O(n2) ,最差: O(n2), 平均: O(n2)
- 空间复杂度: O(1)
- 排序方式: In-place
插入排序(Insertion Sort)
插入排序是一种简单直观的排序算法
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1) 的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间
插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂
插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入
算法步骤
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤 2~5
图解算法
代码实现
1 | /** |
算法分析
- 稳定性: 稳定
- 时间复杂度: 最佳: O(n) ,最差: O(n2), 平均: O(n2)
- 空间复杂度: O(1)
- 排序方式: In-place
希尔排序(Shell Sort)
希尔排序是希尔 (Donald Shell) 于 1959 年提出的一种排序算法
希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为递减增量排序算法,同时该算法是冲破 O(n²) 的第一批算法之一
希尔排序的基本思想是: 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录
基本有序
时,再对全体记录进行依次直接插入排序
算法步骤
我们来看下希尔排序的基本步骤,在此我们选择增量 gap=length/2,缩小增量继续以 gap = gap/2 的方式,这种增量选择我们可以用一个序列来表示,{n/2, (n/2)/2, …, 1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
- 选择一个增量序列 {t1, t2, …, tk},其中 (ti>tj, i<j, tk=1)
- 按增量序列个数 k,对序列进行 k 趟排序
- 每趟排序,根据对应的增量 t,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度
图解算法
代码实现
1 | /** |
算法分析
- 稳定性: 不稳定
- 时间复杂度: 最佳: O(nlogn), 最差: O(n2) 平均: O(nlogn)
- 空间复杂度: O(1)
归并排序 (Merge Sort)
归并排序是建立在归并操作上的一种有效的排序算法
该算法是采用分治法 (Divide and Conquer) 的一个非常典型的应用
归并排序是一种稳定的排序方法
将已有序的子序列合并,得到完全有序的序列
即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 2 - 路归并
和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn)的时间复杂度,代价是需要额外的内存空间
算法步骤
归并排序算法是一个递归过程,边界条件为当输入序列仅有一个元素时,直接返回,具体过程如下:
- 如果输入内只有一个元素,则直接返回,否则将长度为 n 的输入序列分成两个长度为 n/2 的子序列
- 分别对这两个子序列进行归并排序,使子序列变为有序状态
- 设定两个指针,分别指向两个已经排序子序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间(用于存放排序结果),并移动指针到下一位置
- 重复步骤 3~4 直到某一指针达到序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
图解算法
代码实现
1 | /** |
算法分析
- 稳定性: 稳定
- 时间复杂度: 最佳: O(nlogn), 最差: O(nlogn), 平均: O(nlogn)
- 空间复杂度: O(n)
快速排序 (Quick Sort)
快速排序用到了
分治思想
,同样的还有归并排序乍看起来快速排序和归并排序非常相似,都是将问题变小,先排序子串,最后合并
不同的是快速排序在划分子问题的时候经过多一步处理,将划分的两组数据划分为一大一小,这样在最后合并的时候就不必像归并排序那样再进行比较。但也正因为如此,划分的不定性使得快速排序的时间复杂度并不稳定
快速排序的基本思想: 通过一趟排序将待排序列分隔成独立的两部分,其中一部分记录的元素均比另一部分的元素小,则可分别对这两部分子序列继续进行排序,以达到整个序列有序
算法步骤
快速排序使用分治法open in new window(Divide and conquer)策略来把一个序列分为较小和较大的 2 个子序列,然后递回地排序两个子序列。具体算法描述如下:
- 从序列中随机挑出一个元素,做为
基准
(pivot) - 重新排列序列,将所有比基准值小的元素摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个操作结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
- 递归地把小于基准值元素的子序列和大于基准值元素的子序列进行快速排序
算法图解
代码实现
1 |