数据结构与算法系列——排序(13)_鸽巢排序
1. 工作原理(定义)
鸽巢排序(Pigeonhole sort),也被称作基数分类,是一种时间复杂度为O(n)(大O符号)且在不可避免遍历每一个元素并且排序的情况下效率最好的一种排序算法。
2. 算法步骤
1. 给定一个待排序数组,创建一个备用数组(鸽巢),并初始化元素为0,备用数组的索引即是待排序数组的值。
2. 遍历待排序数组,备用数组(鸽巢)存放索引值的个数。
3. 遍历备用数组(鸽巢),将排序值放回原数组得到排序后的数组的值。
3. 性能分析
1. 时间复杂度
- 最坏时间复杂度: O(N+n)
- 最好时间复杂度:O(N+n)
- 平均时间复杂度: O(N+n)
N为待排序数组中最大的元素值。
n为关键字个数
2. 空间复杂度
最坏空间复杂度:O(N*n)
3. 算法稳定性
稳定的算法。
6. 应用
但它只有在差值(或者可被映射在差值)很小的范围内的数值排序的情况下实用。
当涉及到多个不相等的元素,且将这些元素放在同一个"鸽巢"的时候,算法的效率会有所降低。为了简便和保持鸽巢排序在适应不同的情况,比如两个在同一个存储桶中结束的元素必然相等
我们一般很少使用鸽巢排序,因为它很少可以在灵活性,简便性,尤是速度上超过其他排序算法。事实上,桶排序较鸽巢排序更加的实用。
4. 鸽巢排序 & 计数排序 & 桶排序
鸽巢排序的备用数组(鸽巢)存放索引值得个数。
计数排序的备用数组存放的是(对元素值的计数和计数值的累加)来确定确定该序列中值小于x的元素的个数,从而将x直接存放到最终的输出序列的正确位置上。
桶排序是鸽巢排序的一种归纳结果,桶排序较鸽巢排序更加的实用。是计数排序的升级版本。
5. 具体代码
public class PigeonholeSort { /** * 鸽巢排序 * @param array * @return */ public static int[] pigeonholeSort(int[] array) { int length = array.length; int maxNum = getMaxNum(array); int pigeonholeSize = maxNum +1; int [] auxiliary = new int[pigeonholeSize]; int j = 0; for(int i = 0; i < length; ++i){ auxiliary[array[i]]++; } for(int i = 0; i < pigeonholeSize; ++i){ for(int k = 0; k < auxiliary[i]; ++k){ array[j++] = i; } } return array; } // 得到最大值 public static int getMaxNum(int[] array){ int max = array[0]; for (int i = 0; i < array.length; i++) { if(max < array[i]){ max = array[i]; } } return max; } public static void main(String[] args) { int[] A=new int[]{73,22, 93, 43, 55, 14, 28, 65, 39, 81}; A = pigeonholeSort(A); for(int num:A) { System.out.println(num); } } }