基本思想:
将数组中的所有数按位进行分类,由于每一位数的大小都在0~9之间,因此创建下标为0~9的十个数组,根据需要对数进行存储
图文过程:
对于一组数字:8 9 6 11 23 1 9 18 10 213 33 7 87 91 180 35 52 716 106
选择个位数相同的元素,并成为一个数组
此时个位为i的数,分别别存储在下标为i的数组中
对数据开始进行收集,将数组重新整理,数组变为:
10 180 11 1 91 52 23 213 33 35 6 716 106 7 87 8 18 9 9
选择十位数为i的数的元素,并成为一个数组
此时十位为i的数,分别别存储在下标为i的数组中
对数据开始收集,将数组重新整理,数组变为:
1 6 106 7 8 9 9 10 11 213 716 18 23 33 35 52 180 87 91
选择百位数为i的数的元素,并成为一个数组
此时百位为i的数,分别别存储在下标为i的数组中
对数据开始收集,将数组重新整理,数组变为:
1 6 7 8 9 9 10 11 18 23 33 35 52 87 91 106 180 213 716
这样整个数据就排序完成啦!
核心代码实现:
1.上面将数字填表的过程,实际上就是两个数组的叠加dyadic
List<ArrayList> dyadic = new ArrayList<ArrayList>();
该数组的横坐标,即为按照位数分配的下标,每个横坐标(下标)包含了一个数组,这个数组就是按照下标与自己的关系组成的
一共有0~9的取值,所以dyadic.add(new ArrayList())一共实现10次,即由这10个数组组成大数组dyadic
2.接下来是将原数组Array的元素分配给这是个小数组中,由于我们是按照最大数的位数决定循环次数的,因为需要找到整个数组Array的最大元素值,并决定循环次数,以上述数组为例,最大数是716,最高位为3,则循环三次
第一次寻找个位,第二次寻找十位,第三次寻找百位(其他更大数据以此类推)
寻找方法:以数字5432为例
通过上述图解,我们可以推出:位数值 x = num % (int)Math.pow(10, index + 1) / (int)Math.pow(10, index); {注:pow方法是Math类中的,所以需要类名,且该方法是double类型的,所以需要强转成int类型的}
3.找到位数之后,就要将数组array中的元素按照位数和要求进行分类,原理即为图文原理中的图解,共进行times次
for(int j = 0; j < array.length; j++) {
//找出每个数对应的位的数值
int x = array[j] % (int)Math.pow(10, i + 1) / (int)Math.pow(10, i);
//将该数组作为下标,找到对应的子数组
ArrayList arr = dyadic.get(x);
//将该元素添加到子数组中
arr.add(array[j]);
//因为子数组改变,因此更新大数组
dyadic.set(x, arr);
}
4.将分配好的子数组中的值依次赋值给原数组array
//将重新排好的子数组的值依次将需要被排序的数组的值覆盖
int index = 0; //用index作为数组array的下标
//将子数组依次遍历,将每个子数组中的元素添加到array中
for(int k = 0; k < 10; k++) {
//当下标为k的子数组中有元素时
while(dyadic.get(k).size() > 0) {
//得到该数组
ArrayList arr = dyadic.get(k);
///将该数组的第一个元素添加到array中
array[index] = (int)arr.get(0);
//移除子数组中的第一个元素,这样就能在第一个元素被使用之后,后面元素替换
arr.remove(0);
//将array数组中下标也后移一位
index++;
}
}
这样,整个原理过程就完成啦
不过要注意,上述过程只适合正整数的排序,如果是负数的话,就会出现下标越界的异常,但不用担心,因为这种方法同样适用于负整数,只不过需要一些小改动,即要对元素的正负进行判断,如果是负数,则需要绝对值化,并将结果反转即可
完整代码(不含负数)
package sort;
import java.util.ArrayList;
import java.util.List;
public class BasicSort {
public static void basicSort(int[] array) {
//创建叠加数组
List<ArrayList> dyadic = new ArrayList<>();
//给大数组dyadic添加子数组
for(int i = 0; i < 10; i++) {
ArrayList<Integer> arr = new ArrayList<>();
dyadic.add(arr);
}
//找出数组中的最大值
int max = 0;
for(int i = 0; i <array.length; i++) {
if(array[i] > max) {
max = array[i];
}
}
//判断最大值为几位数,其位数就是应该循环的次数
int times = 0;
while(max > 0) {
max /= 10;
times++;
}
//循环times次,每次将对应位的数分配到相应的自数组中
for(int i = 0; i < times; i++) {
for(int j = 0; j < array.length; j++) {
//找出每个数对应的位的数值
int x = array[j] % (int)Math.pow(10, i + 1) / (int)Math.pow(10, i);
//将该数组作为下标,找到对应的子数组
ArrayList arr = dyadic.get(x);
//将该元素添加到子数组中
arr.add(array[j]);
//因为子数组改变,因此更新大数组
dyadic.set(x, arr);
}
//将重新排好的子数组的值依次将需要被排序的数组的值覆盖
int index = 0; //用index作为数组array的下标
//将子数组依次遍历,将每个子数组中的元素添加到array中
for(int k = 0; k < 10; k++) {
//当下标为k的子数组中有元素时
while(dyadic.get(k).size() > 0) {
//得到该数组
ArrayList arr = dyadic.get(k);
///将该数组的第一个元素添加到array中
array[index] = (int)arr.get(0);
//移除子数组中的第一个元素,这样就能在第一个元素被使用之后,后面元素替换
arr.remove(0);
//将array数组中下标也后移一位
index++;
}
}
}
}
}
测试代码
package sort;
import static sort.BasicSort.basicSort;
public class Test {
public static void main(String[] args) {
int[] array = new int[]{2, 9, 1, 32, 31, 6, 22, 0};
basicSort(array);
for(int i : array) {
System.out.println(i);
}
}
}