基数排序 (Radix Sort)

来源:互联网 发布:学单片机需要什么基础 编辑:程序博客网 时间:2024/05/08 07:08

算法原理
———————————————————————————————————
基数排序 (Radix Sort) 是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。
————
排序过程:将所有待比较数值(必须是正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序;然后从桶中倒出所有数,完成一次排序;依次迭代到高位,这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
————
基数排序法会使用到桶 (Bucket),顾名思义,通过将要比较的位(个位、十位、百位…),将要排序的元素分配至 0~9 个桶中,借以达到排序的作用,在某些时候,基数排序法的效率高于其它的比较性排序法。
————
注:基数排序要满足的条件<1>必须是正整数;<2>从低位开始判断,一直迭代到最高位;<3>采用稳定排序。

多关键字排序时有两种解决方案:
最高位优先法(MSD)(Most Significant Digit first)
最低位优先法(LSD)(Least Significant Digit first)
例如,对如下数据序列进行排序。
192,221,12,23
可以观察到它的每个数据至多只有3位,因此可以将每个数据拆分成3个关键字:百位(高位)、十位、个位(低位)。
如果按照习惯思维,会先比较百位,百位大的数据大,百位相同的再比较十位,十位大的数据大;最后再比较个位。人得习惯思维是最高位优先方式。
如果按照人得思维方式,计算机实现起来有一定的困难,当开始比较十位时,程序还需要判断它们的百位是否相同–这就认为地增加了难度,计算机通常会选择最低位优先法。
基数排序方法对任一子关键字排序时必须借助于另一种排序方法,而且这种排序方法必须是稳定的。
对于多关键字拆分出来的子关键字,它们一定位于0-9这个可枚举的范围内,这个范围不大,因此用桶式排序效率非常好。
对于多关键字排序来说,程序将待排数据拆分成多个子关键字后,对子关键字排序既可以使用桶式排序,也可以使用任何一种稳定的排序方法。

此处给出两种实现方法:
<1>采用计数排序来实现基数排序,上一篇中有去实现过计数排序的实现,个人感觉计数排序所选择的桶有可能太多,因为是对于待排序中的最大值和最小值的差距个桶,基数排序所选的桶则为0-9号桶,对于每一位都采用计数排序,则能排好每一位的数,然后利用基数排序从低位到高位的迭代就可以完成排序。从时间和空间上都有所提升。

package 排序;import java.util.Arrays;public class RadixSort {    //基于计数排序的基数排序算法      private static void radixSort(int[] array,int radix, int distance) {          //array为待排序数组          //radix,代表基数          //代表排序元素的位数          int length = array.length;          int[] temp = new int[length];//用于暂存元素          int[] count = new int[radix];//用于计数排序          int divide = 1;          for (int i = 0; i < distance; i++) {              System.arraycopy(array, 0,temp, 0, length);              Arrays.fill(count, 0);              for (int j = 0; j < length; j++) {                  int tempKey = (temp[j]/divide)%radix;                  count[tempKey]++;              }              for (int j = 1; j < radix; j++) {                  count [j] = count[j] + count[j-1];              }              //运用计数排序实现基数排序的重点在下面这个方法                          for (int j = length - 1; j >= 0; j--) {                   //这个必须从后面算,因为count统计的是总数                int tempKey = (temp[j]/divide)%radix;                  count[tempKey]--;                  array[count[tempKey]] = temp[j];              }              divide = divide * radix;                          }      }      /**      * @param args      */      public static void main(String[] args) {          int[] array = {3,2,3,2,5,333,45566,2345678,78,990,12,432,56};          radixSort(array,10,7);          for (int i = 0; i < array.length; i++) {              System.out.print("  " + array[i]);          }      }  }

<2>采用java提供的数据结构Arraylist和LinkedList来实现,具体实现过程中有解释

public static void radixSort(int[] arr) {        if (arr == null || arr.length < 2) {            return;        }        int negNum = 0;         for (int i = 0; i < arr.length; i++) {            //统计正负整数的个数            negNum += arr[i] < 0 ? 1 : 0;        }        int[] negArr = new int[negNum];        int[] posArr = new int[arr.length - negNum];        int negi = 0;        int posi = 0;        for (int i = 0; i < arr.length; i++) {            if (arr[i] < 0) {                negArr[negi++] = -arr[i];            } else {                posArr[posi++] = arr[i];            }        }        radixSortForPositive(negArr);        radixSortForPositive(posArr);        int index = 0;        for (int i = negArr.length - 1; i >= 0; i--) {            arr[index++] = -negArr[i];        }        for (int i = 0; i < posArr.length; i++) {            arr[index++] = posArr[i];        }    }    public static void radixSortForPositive(int[] arr) {        if (arr == null || arr.length < 2) {            return;        }        /*这里的数据结构是,ArrayList中存放的是LinkedList,原因是对于每个桶中的元素要进行调整,所以采用LinkedList;                而对于桶与桶之间只需要进行访问操作,所以选取ArrayList。            对于需要快速插入,删除元素,应该使用LinkedList。            对于需要快速随机访问元素,应该使用ArrayList。*/        ArrayList<LinkedList<Integer>> qArr1 = new ArrayList<LinkedList<Integer>>();        ArrayList<LinkedList<Integer>> qArr2 = new ArrayList<LinkedList<Integer>>();        for (int i = 0; i < 10; i++) {            qArr1.add(new LinkedList<Integer>());            qArr2.add(new LinkedList<Integer>());        }        for (int i = 0; i < arr.length; i++) {            //arr[i] % 10,得到对应的位上的数,get()找到对应的桶,offer()添加到对应的桶            qArr1.get(arr[i] % 10).offer(arr[i]);        }        long base = 10;        while (base <= Integer.MAX_VALUE) {            for (int i = 0; i < 10; i++) {                //get()找到对应的桶                LinkedList<Integer> queue = qArr1.get(i);                while (!queue.isEmpty()) {                    //倒桶                    int value = queue.poll();                    //按从低位到高位迭代                    qArr2.get((int) (value / base) % 10).offer(value);                }            }            ArrayList<LinkedList<Integer>> tmp = qArr1;            qArr1 = qArr2;            qArr2 = tmp;            base *= 10;        }        int index = 0;        for (int i = 0; i < 10; i++) {            LinkedList<Integer> queue = qArr1.get(i);            while (!queue.isEmpty()) {                arr[index++] = queue.poll();            }        }    }
1 0
原创粉丝点击