常见的排序算法有如下几种:
- 插入排序
- 直接插入排序
- 折半插入排序
- 希尔排序
- 选择排序
- 简单选择排序
- 堆排序
- 交换排序
- 冒泡排序
- 快速排序
- 二路归并排序
- 基数排序
- 外部排序
直接插入排序
直接插入排序:新建一个队列(当然也可以不新建,只是麻烦点),将元素依次插入新队列中,保证新队列里的元素是按序插入的。
时间复杂度:O(n^2),空间复杂度O(1),稳定
折半插入排序
折半插入排序:和直接插入排序类似,只是在寻找插入点的时候使用的是二分查找法。对效率略有提高。
时间复杂度:O(n^2),空间复杂度O(1),稳定
希尔排序
希尔排序:按某种分法将待排序列分成几个子序列,对每个子序列进行直接插入排序。但必须保证最后一次的增量是1。
时间复杂度:O(n^2)
或 O(n^1.5)
,空间复杂度O(1),不稳定
冒泡排序
冒泡排序:每次都是两个两个相邻元素比较,每一轮下来总能选出一个元素其位置是固定的。而且,冒泡排序的结束条件是某一轮中没有元素交换。
时间复杂度:O(n^2)
,空间复杂度O(1),稳定
快速排序
快速排序:算是分冶法吧,每次选一个元素出来(通常是第一个),然后将比它小的元素全放它左边,比它大的元素全放它右边。然后再分别对左右两边使用快排(递归)。
时间复杂度:O(nlog2n)
,空间复杂度O(log2n),不稳定
简单选择排序
希尔排序:从待排序列中选择最小(或最大)值与第一个元素交换(当然这个得依次往后挪),因为是交换,所以这也导致了不稳定,不过如果采用的不是交换,而是插入,那么又是稳定的。
时间复杂度:O(n^2)
,空间复杂度O(1),不稳定
堆排序
堆排序:数据结构里的堆和栈是有区别的,当然其他地方也有,但是不一样。这里的堆是指一个完全二叉树,它总能根据一定的变形,使得能很轻松地找出最大(或最小)值。
时间复杂度:O(log2n)
,空间复杂度O(1),不稳定
二路归并排序
二路归并排序:就是通常说的归并排序,将待排序列一分为二,二分为四…这样分下去挨个排好序再合起来。
时间复杂度:O(log2n)
,空间复杂度O(n),稳定
基数排序
基数排序:不是桶排序。不过也使用了“桶”,所谓“桶”其实就是栈,不过是很多个栈,待排序列中最小单位有几个就需要几个栈…三言两语讲不清,请自行查询资料
时间复杂度:O(d(n+rd))
,空间复杂度O(rd),稳定
注:d为关键字的关键字位数;n为关键字数;rd为关键字基的个数
外部排序
外部排序和上面的所有排序算法都不一样。
上述排序都是把数据加载到内存中进行排序,而外部排序之所以不放到内存上是因为数据太多,内存装不下。
常见的方法我们可以采用归并算法,毕竟归并算法是可以先对某一部分排序,最后再来整合即可。
我们这里采用的确实也算归并排序,不过是k路归并排序,不是上面的2路归并了。想来也很好理解,只要我们将数据分为m个部分,每个部分内部是排好序的,那么每次从这m个部分中的最小值中选出一个最小值,就是整个数据的最小值了,就是这样进行排序的。
上述算法当然够了,但是不够好,因此才引出了一些更加高级的算法。
他们的名称和作用分别如下:
- 置换-选择算法:上面将数据分成m个部分了,可是怎么分合适呢?如果m太多的话,想从m个部分中选出一个最小值岂不是也非常耗时,因此我们可以考虑让m尽量小,这时就可以使用这个算法了。它可以从内存读不下的数据中进行排序并生成初始归并段。
- 最佳归并树:数据分成的m个部分长度不一样,而每次归并可能只能进行n路归并(n<=m),如果n<m,则如果数据很多的那一个部分进行I/O的次数就会不同了。这时候应该想到的就是哈弗曼树了,这里就应该是n叉哈夫曼树。
- 败者树:败者树是用来在n个部分中选择最小值用的,正常的话从n个部分中选出最小值需要比较n-1次,而如果是败者树就只要log2n次了。
总结
时间复杂度:快排、归并、堆排序都是O(nlog2n),而希尔排序奇葩点(O(n^2
)或者O(n^1.5))
,了解即可),其他均为O(n^2),哦对了,那个基数排序也是奇葩,它是O(d(n+rd))
空间复杂度:快排是O(log2n),归并是O(n),基数排序是O(rd),其他都是O(1)
稳定性:希尔、快排、简单选择(使用交换而不是插入的情况)、堆排序 不稳定,其他都稳定
注:当只需要查询最大(或最小)的100个的这种情况的时候,如果数据量远大于100,那么使用堆排序效率最高。
上述只是一个总结,并不详细,嘻嘻见谅~~