基数排序详解极其代码实现

基数排序

1、基本原理

定义十个桶,桶的下标分别为0,1,2,3,4,5,6,7,8,9.

下标代表个位,十位或百位······的数字

每次排序对一位进行排序,先对个位进行排序,然后依次对十位、百位·········

示意图如下

在这里插入图片描述

2、具体代码实现

2.1、先得到数组中的最大数从而获取位数。

maxLength为该数组最大数有几位,从而获取下面循环的轮数。

        //首先确定最大数值,以及位数
        int max=arr[0];
        for (int i = 0; i <arr.length ; i++) {
            if(arr[i]>max){
                max=arr[i];
            }
        }
		//maxLength为有几位
        int maxLength=(max+"").length();
2.2、再定义桶

桶是什么,二维数组

int[][] bucket=new int[10][arr.length];

第一个维度10代表0~~9这10个桶。

第二个维度arr.length代表每个桶的容量,由于可能会出现整个数组一位全部相同的情况如【21,31,221,121,51,61,71,231】.此时在排个位的时候所有的数字会放在一个桶中。

二维数组的结构以及上述的情况如下
二维数组的结构以及上述的情况

因此二维数组的两个维度分别为10,arr.length。即为int[][] bucket=new int[10][arr.length];

2.3、将数字放入桶中

再定义一个桶记录数组,用于记录每个桶中的数字的个数。int[] elementCounts=new int[10];

定义一个变量element表示一个数字个位十位百位······的数字。

如:21个位的element为1。elementCounts[element]表示某位为element的数的个数,也就是该桶中数字的个数。

先定义一个循环,控制轮数,每一轮排一个位。轮数由数组中最大的数的位数决定。

再在该循环中再定义一个循环,遍历数组,把分别将数放入相应的桶中。

具体代码如下:

int n=1;//n*10^n后用分别获取十位百位个位······数
//maxLength为位数
//h用于控制轮数,轮数由数组中最大的数的位数决定
for (int h = 0; h < maxLength; h++) {
    //循环遍历数组
    for (int i = 0; i < arr.length ; i++) {
        //计算当前个位十位百位的数值,element为个位,十位·····的数值
        int element=arr[i]/n%10;
        //读一下桶记录器当中的数据,也就是该位中
        int count=elementCounts[element];//数组默认值为0,故count第一次被赋值时为0,count用于记录该位为element的个数
        bucket[element][count]=arr[i];//初始值为bucket[element][0]=arr[0],也就是将个位(其他位)为element的数组元素放入桶中
        elementCounts[element]=elementCounts[element]+1;//elementCounts[element]最开始为0,加一用于统计某位为element的个数
    }//上面的代码实现了将数放入桶中
    n=n*10;
}
2.4、将数字从桶中倒出到原数组中从而完成排序

定义一个index表示原数组下标

然后尝试将bucket[][]中的数字放入原数组arr[]中

先确定第一维i,既是当前位的数字,从小到大。用elementCounts[i]判断当前位的桶中是否有数据

如果当前位的桶中是有数据。那就遍历当前桶(既是当前位位的数字为i的桶)

桶的第二维为j也就是当前桶有多少数据?个数为elementCounts[i]。以其为for循环的边界,遍历bucket[i][],再放入原数组中

最后记得清空桶的记录

int index=0;//原数组下标
for (int i = 0; i <elementCounts.length ; i++) {//i用来表示该位上的数为多少
    if(elementCounts[i]!=0){//elementCounts[i]用于记录该位为i的个数
        for (int j = 0; j < elementCounts[i]; j++) {//j用来表示该位为i的个数
            arr[index]=bucket[i][j];
            index++;
        }
    }
    //清空桶记录
    elementCounts[i]=0;
}
2.5、完整代码
//基数排序
public static void jishusort(int[] arr){
    //首先确定最大数值,以及位数
    int max=arr[0];
    for (int i = 0; i <arr.length ; i++) {
        if(arr[i]>max){
            max=arr[i];
        }
    }
    int maxLength=(max+"").length();
    //桶是什么,二维数组
    //arr.length可能会出现一位全部相同的情况
    int[][] bucket=new int[10][arr.length];
    //定义一个桶记录工具
    int[] elementCounts=new int[10];
    int n=1;
    //maxLength为位数
    //h用于控制论述,通过个十白千位来控制
    for (int h = 0; h < maxLength; h++) {
        //循环遍历数组
        for (int i = 0; i < arr.length ; i++) {
            //计算当前个位十位百位的数值,element为个位,十位…………的数值
            int element=arr[i]/n%10;
            //读一下桶记录器当中的数据,也就是该位中
            int count=elementCounts[element];//数组默认值为0,故count第一次被赋值时为0,count用于记录该位为element的个数
            bucket[element][count]=arr[i];//初始值为bucket[][0]=arr[0],也就是将个位(其他位)为element的数组元素放入桶中
            elementCounts[element]=elementCounts[element]+1;//elementCounts[element]最开始为0,加一用于统计某位为element的个数
        }//上面的代码实现了将数放入桶中
        int index=0;//原数组下标
        for (int i = 0; i <elementCounts.length ; i++) {//i用来表示该位上的数为多少
            if(elementCounts[i]!=0){//elementCounts[i]用于记录该位为i的个数
                for (int j = 0; j < elementCounts[i]; j++) {//j用来表示该位为i的个数
                    arr[index]=bucket[i][j];
                    index++;
                }
            }
            //清空桶记录
            elementCounts[i]=0;
        }
        n=n*10;
    }
    System.out.println("排序后为:"+Arrays.toString(arr));
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java动态代理是一种通过在运行时期间生成代理对象来实现对目标对象进行代理的技术。它可以在不修改目标对象的情况下,为目标对象提供额外的功能。 Java动态代理实现的核心是利用了Java的反射机制和动态生成类的技术。在动态代理中,我们需要定义一个代理类和一个实现了InvocationHandler接口的处理器类。 代理类是在运行时动态生成的类,它是目标对象的代理,它实现了与目标对象相同的接口,并且在方法调用时会通过InvocationHandler接口的实现类来处理方法的调用。InvocationHandler接口中只有一个方法invoke(Object proxy, Method method, Object[] args),这个方法就是用来处理方法调用的。 下面是一个简单的Java动态代理的示例代码: ``` import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method"); Object result = method.invoke(target, args); System.out.println("after method"); return result; } public static void main(String[] args) { RealObject realObject = new RealObject(); DynamicProxy dynamicProxy = new DynamicProxy(realObject); Interface proxyObject = (Interface) Proxy.newProxyInstance( Interface.class.getClassLoader(), new Class[] { Interface.class }, dynamicProxy); proxyObject.doSomething(); } } interface Interface { void doSomething(); } class RealObject implements Interface { public void doSomething() { System.out.println("RealObject doSomething"); } } ``` 在这个示例中,我们定义了一个DynamicProxy类作为代理处理器,它实现了InvocationHandler接口。在DynamicProxy类中,我们定义了一个Object类型的target属性,它表示目标对象。 在DynamicProxy类的invoke方法中,我们先输出了一句话“before method”,然后通过反射机制调用目标对象的方法,最后输出了一句话“after method”。 在DynamicProxy类的main方法中,我们首先创建了一个RealObject对象作为目标对象,然后创建了一个DynamicProxy对象,并将RealObject对象作为参数传递给DynamicProxy对象的构造方法。接着,我们通过Proxy.newProxyInstance方法动态生成了一个代理对象,并将DynamicProxy对象作为参数传递给它。最后,我们调用代理对象的doSomething方法。 当我们运行这个程序时,它会输出以下内容: ``` before method RealObject doSomething after method ``` 这表明,在代理对象调用doSomething方法时,它会先调用DynamicProxy类的invoke方法,在invoke方法中,我们将先输出一句话“before method”,然后调用目标对象的方法,最后输出一句话“after method”。 Java动态代理的优点是可以在运行时期间动态生成代理对象,不需要预先定义代理类,这样可以大大减少代码量。同时,Java动态代理也具有很好的灵活性,可以对不同的目标对象生成不同的代理对象,实现不同的处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值