计数排序
前言:
这是一种不需要比较的排序方式,但极其浪费空间。(写嵌入式的小伙伴会气死吧)
原理:
统计每个整数在序列中出现的次数,进而推导出每个整数在有序序列中的索引
示例:
//这是最简单的实现方式// 找出最大值int max = array[0];for (int i = 1; i < array.length; i++) {if (array[i] > max) {max = array[i];}} // O(n)// 开辟内存空间,存储每个整数出现的次数int[] counts = new int[1 + max];// 统计每个整数出现的次数for (int i = 0; i < array.length; i++) {counts[array[i]]++;} // O(n)// 根据整数的出现次数,对整数进行排序int index = 0;for (int i = 0; i < counts.length; i++) {while (counts[i]-- > 0) {array[index++] = i;}} // O(n)
算法分析:
这个版本的实现存在以下问题:无法对负整数进行排序;极其浪费内存空间;是个不稳定的排序 。
(用这个的人就很神奇)
计数排序 – 改进思路
原本我们是把数组的索引作为记录原序列中的数值,但是数组中没有负数,所以我们就没有办法比较序列中的负数。
现在我们将数组中第一个位置就是序列中最小的数,利用这个数和数组索引的差,
解决的不能负数的问题,现在来解决不稳定
假设array中的最小值是 min; array中的元素 k 对应的 counts 索引是 k – min; array中的元素 k 在有序序列中的索引; counts[k – min] – p; p 代表着是倒数第几个 k; 

// 找出最值int max = array[0];int min = array[0];for (int i = 1; i < array.length; i++) {if (array[i] > max) {max = array[i];}if (array[i] < min) {min = array[i];}}// 开辟内存空间,存储次数int[] counts = new int[max - min + 1];// 统计每个整数出现的次数for (int i = 0; i < array.length; i++) {counts[array[i] - min]++;}// 累加次数for (int i = 1; i < counts.length; i++) {counts[i] += counts[i - 1];}// 从后往前遍历元素,将它放到有序数组中的合适位置int[] newArray = new int[array.length];for (int i = array.length - 1; i >= 0; i--) {newArray[--counts[array[i] - min]] = array[i];}// 将有序数组赋值到arrayfor (int i = 0; i < newArray.length; i++) {array[i] = newArray[i];}}
基数排序
前言:
基数排序,所谓的基数就是他的个位,十位,百位,通过个十百千的顺序依次排列各位的数字大小,最后得到所有数字的大小。
原理:
基数排序非常适合用于整数排序(尤其是非负整数),因此只演示对非负整数进行基数排序 执行流程:依次对个位数、十位数、百位数、千位数、万位数…进行排序(从低位到高位)
对位数排序时,我们使用计数排序
示例:
// 找出最大值int max = array[0];for (int i = 1; i < array.length; i++) {if (array[i] > max) {max = array[i];}}// 个位数: array[i] / 1 % 10 = 3// 十位数:array[i] / 10 % 10 = 9// 百位数:array[i] / 100 % 10 = 5// 千位数:array[i] / 1000 % 10 = ...for (int divider = 1; divider <= max; divider *= 10) {countingSort(divider);}protected void countingSort(int divider) {// 开辟内存空间,存储次数int[] counts = new int[10];// 统计每个整数出现的次数for (int i = 0; i < array.length; i++) {counts[array[i] / divider % 10]++;}// 累加次数for (int i = 1; i < counts.length; i++) {counts[i] += counts[i - 1];}// 从后往前遍历元素,将它放到有序数组中的合适位置int[] newArray = new int[array.length];for (int i = array.length - 1; i >= 0; i--) {newArray[--counts[array[i] / divider % 10]] = array[i];}// 将有序数组赋值到arrayfor (int i = 0; i < newArray.length; i++) {array[i] = newArray[i];}}
基数排序 – 另一种思路
我们先按照个位数的大小竖着放起来
然后,我们依次将数穿起来,最后,就会把数列排好
示例:
// 找出最大值
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
//用来记录的二维数组
int buckets[][]=new int[10][array.length];
//二维数组每列的数量
int bucketSizes[]=new int[buckets.length];
for (int divider = 1; divider <= max; divider *= 10){
for (int i=0;i<array.length;i++){
int a=array[i] / divider % 10;
buckets[a][bucketSizes[a]++]=array[i];
}
int index=0;
for (int i=0;i<buckets.length;i++){
for (int j=0;j<bucketSizes[i];j++){
array[index++]=buckets[i][j];
}
bucketSizes[i]=0;
}
}
