排序算法-------基数排序RadixSort

/**
 * 基数排序 基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。
 * 然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
 * 基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。
 * 由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数, 所以基数排序也不是只能使用于整数。 步驟:
 * 1、将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。 2、从最低位开始,依次进行一次排序。
 * 3、这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
 * 
 * @author Administrator
 *
 */

public class RadixSort {

    /**
     * 方法1 :利用一维数据,根据每一位上的数值的位置,借助中间数组,重新给原数组赋值
     * @param arr
     */

    public static void radixSort(int[] arr) {
        int[] tempArr = new int[arr.length];
        int max = getMax(arr);
        // 从低位往高位循环
        for (int d = 1; d <= max; d++) {
            // 用于存放0-9各位数的数字
            int[] count = new int[10];
            // 获得各位上的数字
            for (int i = 0; i < arr.length; i++) {
                int digit = getDigit(arr[i], d);
                count[digit] += 1;// 统计该位上有多少个数字 比如第一位上0有多少个
            }
            /*
             * 比如某次经过上面统计后结果为:[0, 2, 3, 3, 0, 0, 0, 0, 0, 0]则经过下面计算后 结果为: [0, 2,
             * 5, 8, 8, 8, 8, 8, 8, 8]但实质上只有如下[0, 2, 5, 8, 0, 0, 0, 0, 0, 0]中
             * 非零数才用到,因为其他位不存在,它们分别表示如下:2表示比较位为1的元素可以存放在索引为1、0的
             * 位置,5表示比较位为2的元素可以存放在4、3、2三个(5-2=3)位置,8表示比较位为3的元素可以存放在
             * 7、6、5三个(8-5=3)位置
             */

            //获得0-9各个位上有几位数字。总共有几个数据
            for (int i = 1; i < 10; i++) {
                count[i] += count[i - 1];
            }
            /*
             * 注:这里只能从数组后往前循环,因为排序时还需保持以前的已排序好的 顺序,不应该打
             * 乱原来已排好的序,如果从前往后处理,则会把原来在前面会摆到后面去,因为在处理某个
             * 元素的位置时,位记数器是从大到到小(count[digit(arr[i], d)]--)的方式来处
             * 理的,即先存放索引大的元素,再存放索引小的元素,所以需从最后一个元素开始处理。
             * 如有这样的一个序列[212,213,312],如果按照从第一个元素开始循环的话,经过第一轮
             * 后(个位)排序后,得到这样一个序列[312,212,213],第一次好像没什么问题,但问题会
             * 从第二轮开始出现,第二轮排序后,会得到[213,212,312],这样个位为3的元素本应该
             * 放在最后,但经过第二轮后却排在了前面了,所以出现了问题
             */
            for (int i = arr.length - 1; i >= 0; i--) {// 只能从最后一个元素往前处理
                // for (int i = 0; i < arr.length; i++) {//不能从第一个元素开始循环
                //根据count[getDigit(arr[i], d)]把元素中的数放入不同的位置。
                tempArr[count[getDigit(arr[i], d)] - 1] = arr[i];
                count[getDigit(arr[i], d)]--;
            }
             for (int i = 0; i < arr.length; i++) {
                    arr[i] = tempArr[i];
             }
            ////System.arraycopy(tmpArray, 0, arr, 0, tmpArray.length);
        }
    }
    /**
     * 方法2 :利用二维数组,第一维代表某一位上的值,第二维里面封装待排序数组中的元素。
     * 最后从0-9 ,取出二维数组中的元素
     * 
     * @param arr
     */
    public static void radixSort2(int[] arr) //d表示最大的数有多少位
    {
        int k = 0;
        int n = 1;
        int m = 1; //控制键值排序依据在哪一位
        int[][] temp = new int[10][arr.length]; //数组的第一维表示可能的余数0-9
        int[] order = new int[10]; //数组order[i]用来表示该位是i的数的个数
        int d = getMax(arr);//获得最大值的位数
        while(m <= d)
        {
            for(int i = 0; i < arr.length; i++)
            {
                int lsd = (arr[i] / n) % 10;//arr[i]某一位上的数值
                temp[lsd][order[lsd]] = arr[i];//最初状态是0,之后值会被覆盖,后面的值个数少也没关系,可以由order数组来控制。
                order[lsd]++;
            }
            for(int i = 0; i < 10; i++)
            {
                if(order[i] != 0)//是0 代表该位上没有数
                    for(int j = 0; j < order[i]; j++)
                    {
                        arr[k] = temp[i][j];//k从0开始递增,按照某一位进行了排序
                        k++;
                    }
                order[i] = 0;//order归零
            }
            n *= 10;//取下一位余数的阶乘数
            k = 0;//k归零,使不影响下一次循环
            m++;
        }
    }

    /**
     * 获取最大数的位数,方便比较
     * 
     * @param arr
     * @return 最大数的位数
     */
    public static int getMax(int[] arr) {
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (max < arr[i]) {
                max = arr[i];
            }
        }
        int numOfDigit = 0;
        while (max > 0) {
            max = max / 10;
            numOfDigit++;
        }
        return numOfDigit;
    }

    /**
     * 返回第d位的个数
     * 
     * @param n
     *            需要求的参数
     * @param d
     *            参数的第d位
     * @return
     */
    public static int getDigit(int n, int d) {
        int power = 1;
        while (--d > 0) {
            power = power * 10;
        }
        return n/power%10;
    }

    public static void main(String[] args) {

         int[] data = {73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 10};

            radixSort2(data);
            for (int i = 0; i < data.length; i++) {
                System.out.print(data[i] + " ");
            }

    }

}

猜你喜欢

转载自blog.csdn.net/weixin_42061676/article/details/81093410
今日推荐