zoukankan      html  css  js  c++  java
  • 数据结构与算法——基数排序简单Java实现

      基数排序(radix sort)又称“桶子法”,在对多个正整数进行排序时可以使用。它的灵感来自于队列(Queue),它最独特的地方在于利用了数字的有穷性(阿拉伯数字只有0到9的10个)。

      基数排序使用11个动态数组实现排序算法,一个主队列(下文都将使用的动态数组称为队列)存储未排序的数据(最后排序完成也仍然可以用它存储,或者如果希望保存原来的数据位置则可能需要增加一个队列);10个子队列用于排序过程中动态存放数值,在排序开始前和结束后可以清空。

      我们使用LinkedList类来实现基数排序,其实整个类很简单,我先贴出全部代码然后再细细解释:

      1 package ahe.sort;
      2 
      3 import java.io.BufferedReader;
      4 import java.io.IOException;
      5 import java.io.InputStreamReader;
      6 import java.util.LinkedList;
      7 
      8 /**
      9  * 基数排序算法
     10  * 
     11  * @author Johness
     12  *
     13  */
     14 public class RadixSort {
     15 
     16     /** 主队列 */
     17     private LinkedList<Integer> mainQueue;
     18     /** 子队列 */
     19     private LinkedList<Integer>[] subQueues;
     20     /** 子队列个数,作用不大 */
     21     private final int SIZE = 10;
     22     /** 当前容器(主队列)中存储数值的最大位数 */
     23     private int maxDigits;
     24     
     25     /** 构造函数 */
     26     public RadixSort() {
     27         mainQueue = new LinkedList<Integer>();
     28         subQueues = new LinkedList[SIZE];
     29         for(int i = 0; i < SIZE; ++i)
     30             subQueues[i] = new LinkedList<Integer>();
     31         maxDigits = 0;
     32     }
     33     
     34     /** 向容器中(主队列)添加一个数值 */
     35     public void add(Integer num) {
     36         int digits = String.valueOf(num).length();
     37         if (digits > maxDigits)
     38             maxDigits = digits;
     39         mainQueue.add(num);
     40     }
     41     
     42     /** 排序 */
     43     public void sort() {
     44         for (int i = 1; i <= maxDigits; ++i) {
     45             while (mainQueue.size() > 0) {
     46                 Integer element = (Integer) mainQueue.pop();
     47                 String elementTmpStr = String.valueOf(element);
     48                 if (elementTmpStr.length() < i) {
     49                     subQueues[0].add(element);
     50                     continue;
     51                 }
     52                 int digit = elementTmpStr.charAt(elementTmpStr.length() - i) - '0';
     53                 subQueues[digit].add(element);
     54             }
     55             //listSubQueues();
     56             for (int j = 0; j < SIZE; ++j) {
     57                 mainQueue.addAll(subQueues[j]);
     58                 subQueues[j].clear();
     59             }
     60             //listMainQueue();
     61         }
     62     }
     63     
     64     /*==============================================================================================*/
     65     // 以下方法为测试方法(以下方法来自于Arizona State University学校课后作业,本人只做翻译,如该资源侵犯了您的权益,请及时联系我)
     66     // 您可以访问
     67     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/Assignment11.java
     68     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/Sorting.java
     69     // 查看本文参考内容
     70     // 本文输入输出对照表可从该课后作业中获得
     71     // 输入表
     72     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input1.txt
     73     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input2.txt
     74     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input3.txt
     75     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input4.txt
     76     // 输出表
     77     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output1.txt
     78     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output2.txt
     79     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output3.txt
     80     // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output4.txt
     81     /*==============================================================================================*/
     82     /**
     83      * 列举(输出)主队列数据
     84      */
     85     public void listMainQueue() {
     86         System.out.println("mainQueue = " + listQueue(mainQueue) + "
    ");
     87     }
     88 
     89     /**
     90      * 列举(输出)子队列数据
     91      */
     92     public void listSubQueues() {
     93         String result = "";
     94         for (int i = 0; i < SIZE; i++) {
     95             result += "subQueue[" + i + "]:";
     96             result += listQueue(subQueues[i]);
     97             result += "
    ";
     98         }
     99         System.out.println(result);
    100     }
    101 
    102     /**
    103      * 列举某队列中数据项
    104      * 
    105      * 方法使用了一个临时队列来完成数据轮循
    106      * 先从目标队列中逐个取出(采用取出并删除的方式)放入临时队列并做列举操作(连接到返回字符串)
    107      * 待轮循完成后再将临时队列中的数据存入回目标队列
    108      * 
    109      * @param queue 目标队列
    110      * @return 包含目标队列中所有数据的字符串
    111      */
    112     private String listQueue(LinkedList<Integer> queue) {
    113         LinkedList<Integer> temp = new LinkedList<Integer>();
    114         String result = "{ ";
    115 
    116         while (!queue.isEmpty()) {
    117             Integer removed = queue.remove();
    118             result += removed + " ";
    119             temp.offer(removed);
    120         }
    121         result += "}
    ";
    122 
    123         while (!temp.isEmpty()) {
    124             Integer removed2 = temp.remove();
    125             queue.offer(removed2);
    126         }
    127         return result;
    128     }
    129     
    130     public static void main(String[] args) {
    131         char input1;
    132         String inputInfo = new String();
    133         String line = new String();
    134 
    135         RadixSort sort1 = new RadixSort();
    136 
    137         try {
    138             // 打印菜单
    139             printMenu();
    140 
    141             // 创建流读取器读取用户输入
    142             InputStreamReader isr = new InputStreamReader(System.in);
    143             BufferedReader stdin = new BufferedReader(isr);
    144 
    145             do {
    146                 System.out.print("你想进行什么操作?
    ");
    147                 line = stdin.readLine().trim(); // 读取一行
    148                 input1 = line.charAt(0);
    149                 input1 = Character.toUpperCase(input1);
    150 
    151                 if (line.length() == 1) // 检查输入指令是否为单个
    152                                         // 字符
    153                 {
    154                     switch (input1) {
    155                     case 'A': // 添加一个数值
    156                         System.out.print("请输入要添加的数值:
    ");
    157                         inputInfo = stdin.readLine().trim();
    158                         int num = Integer.parseInt(inputInfo);
    159                         sort1.add(num);
    160                         System.out.print("数值添加成功
    ");
    161                         break;
    162                     case 'L': // 列举数值
    163                         sort1.listMainQueue();
    164                         break;
    165                     case 'Q': // 退出
    166                         break;
    167                     case 'S': // 排序
    168                         sort1.sort();
    169                         System.out.print("排序完成
    ");
    170                         break;
    171                     case '?': // 显示帮助
    172                         printMenu();
    173                         break;
    174                     default:
    175                         System.out.print("未知指令
    ");
    176                         break;
    177                     }
    178                 } else {
    179                     System.out.print("未知指令
    ");
    180                 }
    181             } while (input1 != 'Q' || line.length() != 1);
    182         } catch (IOException exception) {
    183             System.out.print("IO Exception
    ");
    184         }
    185     }
    186 
    187     /** 打印控制台界面(菜单) */
    188     public static void printMenu() {
    189         System.out.print("选项		动作
    " + "------		------
    "
    190                 + "A		添加一个数值
    " + "L		列举队列
    "
    191                 + "Q		退出
    " + "S		排序数据
    "
    192                 + "?		显示帮助
    
    ");
    193     }
    194 }

      我们直接看sort方法(行43至62),在略去了每次排序数据从子队列存回主队列的代码(行56至59)后我们的排序算法主要分为两层。

      外层一共需要循环最大数值位数次,内层(每次)则是需要循环数值个数次。以{1,22,333,4444}为例,外层为4次循环(最大数4444为4位数),内层为4次循环(共有4个元素需要排序)。

      我们把排序过程中列举队列的代码取消注释(行55和60),我们使用输入表1进行输入:

    a
    539
    a
    264
    a
    372
    a
    424
    a
    419
    a
    129
    a
    322
    a
    544
    a
    367
    l
    s
    l
    q

      对应输出表则应该如下(部分空白我去除了):

     1 选项        动作
     2 ------        ------
     3 A        添加一个数值
     4 L        列举队列
     5 Q        退出
     6 S        排序数据
     7 ?        显示帮助
     8 
     9 你想进行什么操作?
    10 a
    11 请输入要添加的数值:
    12 539
    13 数值添加成功
    14 你想进行什么操作?
    15 a
    16 请输入要添加的数值:
    17 264
    18 数值添加成功
    19 你想进行什么操作?
    20 a
    21 请输入要添加的数值:
    22 372
    23 数值添加成功
    24 你想进行什么操作?
    25 a
    26 请输入要添加的数值:
    27 424
    28 数值添加成功
    29 你想进行什么操作?
    30 a
    31 请输入要添加的数值:
    32 419
    33 数值添加成功
    34 你想进行什么操作?
    35 a
    36 请输入要添加的数值:
    37 129
    38 数值添加成功
    39 你想进行什么操作?
    40 a
    41 请输入要添加的数值:
    42 322
    43 数值添加成功
    44 你想进行什么操作?
    45 a
    46 请输入要添加的数值:
    47 544
    48 数值添加成功
    49 你想进行什么操作?
    50 a
    51 请输入要添加的数值:
    52 367
    53 数值添加成功
    54 你想进行什么操作?
    55 l
    56 mainQueue = { 539 264 372 424 419 129 322 544 367 }
    57 你想进行什么操作?
    58 s
    59 subQueue[0]:{ }
    60 subQueue[1]:{ }
    61 subQueue[2]:{ 372 322 }
    62 subQueue[3]:{ }
    63 subQueue[4]:{ 264 424 544 }
    64 subQueue[5]:{ }
    65 subQueue[6]:{ }
    66 subQueue[7]:{ 367 }
    67 subQueue[8]:{ }
    68 subQueue[9]:{ 539 419 129 }
    69 mainQueue = { 372 322 264 424 544 367 539 419 129 }
    70 subQueue[0]:{ }
    71 subQueue[1]:{ 419 }
    72 subQueue[2]:{ 322 424 129 }
    73 subQueue[3]:{ 539 }
    74 subQueue[4]:{ 544 }
    75 subQueue[5]:{ }
    76 subQueue[6]:{ 264 367 }
    77 subQueue[7]:{ 372 }
    78 subQueue[8]:{ }
    79 subQueue[9]:{ }
    80 mainQueue = { 419 322 424 129 539 544 264 367 372 }
    81 subQueue[0]:{ }
    82 subQueue[1]:{ 129 }
    83 subQueue[2]:{ 264 }
    84 subQueue[3]:{ 322 367 372 }
    85 subQueue[4]:{ 419 424 }
    86 subQueue[5]:{ 539 544 }
    87 subQueue[6]:{ }
    88 subQueue[7]:{ }
    89 subQueue[8]:{ }
    90 subQueue[9]:{ }
    91 mainQueue = { 129 264 322 367 372 419 424 539 544 }
    92 排序完成
    93 你想进行什么操作?
    94 l
    95 mainQueue = { 129 264 322 367 372 419 424 539 544 }
    96 你想进行什么操作?
    97 q

      (你可以将列举子队列的语句行55放入输出更频繁的地方如原行49后和52后,这样更加能直观地看到效果)

      从上面的输出表可以看出,排序轮循一共进行了3次(外层,因为数值最大位数为3)。

      好,不多说了,大家领会精神。

     欢迎您移步我们的交流群,无聊的时候大家一起打发时间:Programmer Union

     或者通过QQ与我联系:点击这里给我发消息

     (最后编辑时间2013-11-22 22:38:04)

  • 相关阅读:
    Java21-统计字符串中每个字符出现的次数
    算法练习之字符串切割及统计每个字符出现的次数
    Java20-HashMap
    Java19-hashSet
    Java18-泛型的基础知识
    Java17-foreach循环遍历
    Java16-【转载】ArrayList和LinkedList的区别
    Unity查看Editor下PlayerPrefs信息
    Unity下自定义快捷键创建UGUI元素
    Unity中去除贴图中多余的透明区域
  • 原文地址:https://www.cnblogs.com/Johness/p/3438371.html
Copyright © 2011-2022 走看看