线性排序
- 线性排序即时间复杂度为O(n)的排序算法
- 桶排序------>分桶+归并排序-->取出结果
- 计数排序------>分桶+计数-->先统计计数,再取出来,实现排序
- 基数排序------>在每个位上桶排序
- 桶排序的思想可用来对数据分类
桶排序--将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序(桶内使用归并排序保证稳定性),再把每个桶里的数据按照顺序依次取出
- 适合用于外部排序(数据存储在磁盘),数据量比较大,内存不足时,把数据按区间分成若干个桶,每次处理一个桶
计数排序--获取数据项大小范围,设置 “范围大小+1” 个桶,n个桶只代表0~n-1个数字,分别对值为每个桶代表的数字的数据项计数,放入对应桶,再对桶顺序求和放入桶,最后从后遍历数据项,取对应下标桶的计数为其排序后下标,取完桶计数减一,遍历完则排序完成。
- 计数排序只能用在数据范围不大的场景中,如果数据范围 k 比要排序的数据 n 大很多,就不适合用计数排序了。而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大小的情况下,转化为非负整数。
- 应用如:高考分数排名
- 伪代码
-
// 计数排序,a是数组,n是数组大小。假设数组中存储的都是非负整数。 public void countingSort(int[] a, int n) { if (n <= 1) return; // 查找数组中数据的范围 int max = a[0]; for (int i = 1; i < n; ++i) { if (max < a[i]) { max = a[i]; } } int[] c = new int[max + 1]; // 申请一个计数数组c,下标大小[0,max] for (int i = 0; i <= max; ++i) { c[i] = 0; } // 计算每个元素的个数,放入c中 for (int i = 0; i < n; ++i) { c[a[i]]++; } // 依次累加 for (int i = 1; i <= max; ++i) { c[i] = c[i-1] + c[i]; } // 临时数组r,存储排序之后的结果 int[] r = new int[n]; // 计算排序的关键步骤,有点难理解 for (int i = n - 1; i >= 0; --i) { int index = c[a[i]]-1; r[index] = a[i]; c[a[i]]--; } // 将结果拷贝给a数组 for (int i = 0; i < n; ++i) { a[i] = r[i]; } }
基数排序--对等长数据项进行排序,为保持稳定,从最后一位开始,每次按数据项的一位进行排序,排序过程可用桶排序或计数排序,各位排序完成则排序完成,复杂度O(k*n),k为位数
- 基数排序对要排序的数据是有要求的,需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果 a 数据的高位比 b 数据大,那剩下的低位就不用比较了。除此之外,每一位的数据范围不能太大,要可以用线性排序算法来排序,否则,基数排序的时间复杂度就无法做到 O(n) 了。
- 应用如:手机号排序