Java常用的八种排序算法与代码实现(三):桶排序、计数排序、基数排序

三种线性排序算法:桶排序、计数排序、基数排序

线性排序算法(Linear Sort):这些排序算法的时间复杂度是线性的O(n),是非比较的排序算法

桶排序(Bucket Sort)
  将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序,桶内排完序之后,再把桶里的数据按照顺序取出,组成的序列就是有序的了
桶排序比较适合用在外部排序中,比如磁盘中的数据需要   排序而内存有限,没有办法将数据全部加载的情况
桶排序步骤:
  1.找出待排序数组中的最大值max、最小值min
  2. 动态数组ArrayList 作为桶,桶里放的元素也用 ArrayList 存储。桶的数量为(max-min)/arr.length+1
  3.遍历数组 arr,计算每个元素 arr[i] 放的桶
  4.每个桶各自排序
  5.遍历桶数组,把排序好的元素放进输出数组
图解:
在这里插入图片描述在这里插入图片描述
代码:

/**
   * 桶排序
   *
   * @param arr 待排数组
   */
  public static void bucketSort(int[] arr) {
    int min = arr[0];
    int max = arr[0];
    // 获取数据范围
    for (int i = 1; i < arr.length; i++) {
      if (arr[i] > max) {
        max = arr[i];
      }
      if (arr[i] < min) {
        min = arr[i];
      }
    }
    // 确定桶数
    int count = (min + max) / arr.length + 1;
    ArrayList<ArrayList<Integer>> bucket = new ArrayList<>(count);
    for (int i = 0; i < count; i++) {
      bucket.add(new ArrayList<>());
    }
    // 将元素放入桶
    for (int i = 0; i < arr.length; i++) {
      int num = (arr[i] - min) / arr.length;
      bucket.get(num).add(arr[i]);
    }
    // 将桶中数据进行排序(排序已经完成)
    for (ArrayList<Integer> arrayList : bucket) {
      Collections.sort(arrayList);
    }
    // 将桶中数据导入待排序的数组中(只是为了显示方便)
    int k = 0;
    for (int i = 0; i < bucket.size(); i++) {
      for (int j = 0; j < bucket.get(i).size(); j++) {
        arr[k++] = bucket.get(i).get(j);
      }
    }
  }

计数排序(Counting Sort)
  桶排序的一种特殊情况,当要排序的n个数据,所处的范围并不大的时候,比如最大值是k,我们就可以把数据划分成k个桶,每个桶的表数据值都是相同的,省掉了桶内排序的步骤,在显示生活中也存在这样的案例,比如高考省榜,就是按照这种排序方式进行排列的(主要适用于数据比较集中的情况)

计数排序步骤:
  1 求出待排序列的最大值和最小值
  2 设定一个计数数组,用来记录每个元素出现的次数
  3 记录待排序列在计数数组中的位置和次数
  4 将计数数组中的数据灌入待排序列中
图解:
在这里插入图片描述  计数排序在生活中的应用:—— 高考省榜
在这里插入图片描述
代码:

/**
   * 计数排序
   *
   * @param arr 待排数组
   */
  public static void countingSort(int[] arr) {
    int min = arr[0];
    int max = arr[0];
    // 获取数据范围
    for (int i = 1; i < arr.length; i++) {
      if (arr[i] > max) {
        max = arr[i];
      }
      if (arr[i] < min) {
        min = arr[i];
      }
    }
    // 创建计数数组count,用来记录数据出现的次数
    int[] count = new int[max - min + 1];
    for (int i = 0; i < arr.length; i++) {
      count[arr[i] - min]++;
    }
    // 将计数数组中的数据灌入待排序数组
    int k = 0;
    for (int i = 0; i < count.length; i++) {
      if (count[i] != 0) {
        for (int j = 0; j < count[i]; j++) {
          arr[k++] = i + min;
        }
      }
    }
  }

基数排序(Radix Sort)
  基数排序对要排序的数据有要求,需要可以分割出独立的”位”进行比较,而且位与位之间有递进关系,如果a数据的高位比b数据大,那剩下的地位就不用比较了,除此之外每一位的数据范围不能太大,要可以用线性排序算法来排序,否则基数排序的时间复杂度就无法做到O(n)

基数排序的步骤:
  1 找出待排序列的未排高位
  2 用线性排序按照未排高位进行线性排序,然后重复1过程,直至序列全部有序
图解:
在这里插入图片描述
代码:

/**
   * 基数排序
   *
   * @param arr 待排数组
   * @param len 待排位数
   */
  public static void radixSort(int[] arr, int len) {
    // 除数,从8位0开始,先比较高位
    int divisor = (int) Math.pow(10, len);
    // 确定桶数,桶的数量可设为10,因为位数的取值为0-9,并初始化桶
    ArrayList<ArrayList<Integer>> bucket = new ArrayList<>(10);
    for (int i = 0; i < 10; i++) {
      bucket.add(new ArrayList<>());
    }
    for (int i = 0; i < arr.length; i++) {
      // 只取个位
      int c = (arr[i] / divisor) % 10;
      bucket.get(c).add(arr[i]);
    }
    // 将桶中数据进行排序(排序已经完成)
    for (ArrayList<Integer> arrayList : bucket) {
      Collections.sort(arrayList);
    }
    // 将桶中数据导入待排序的数组中
    int k = 0;
    for (int i = 0; i < bucket.size(); i++) {
      for (int j = 0; j < bucket.get(i).size(); j++) {
        arr[k++] = bucket.get(i).get(j);
      }
    }
  }

测试类及生成随机数组,随机订单的方法(基数排序的数据是50个8位订单号)

/**
   * 生成一个长度5-10的随机数组
   *
   * @return 随机数组
   */
  private static int[] initArray() {
    int len = 5 + new Random().nextInt(6);
    int[] arr = new int[len];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = new Random().nextInt(100);
    }
    return arr;
  }

  /**
   * 为基数排序法准备的8位随机订单,50组数据
   *
   * @return 随机订单数组
   */
  private static int[] initArrayForRadixSort() {
    String str = "";
    int[] arr = new int[50];
    Random random = new Random();
    for (int i = 0; i < arr.length; i++) {
      // 保证订单首位数不为0,所以随机0-9生成后7位,随机1-9生成第一位
      for (int j = 0; j < 7; j++) {
        str += random.nextInt(10);
      }
      str = 1 + random.nextInt(9) + str;
      arr[i] = Integer.valueOf(str);
      str = "";
    }
    return arr;
  }

public static void main(String[] args) {

    // 基数排序
    int[] arr = initArrayForRadixSort();
    System.out.println("排序之前的数组是:" + Arrays.toString(arr));
    int count = (arr[0] + "").length() - 1;
    for (int i = count; i < arr.length; i++) {
      countingSort(arr, i);
    }
    System.out.println("排序之后的数组是:" + Arrays.toString(arr));

    // 非基数排序
   int[] arr2 = initArray();
    System.out.println("排序之前的数组是:" + Arrays.toString(arr2));
    quockSort(arr2);
    System.out.println("排序之后的数组是:" + Arrays.toString(arr2));
  }

测试结果,亲测有效:

桶排序:
  排序之前的数组是:[31, 64, 46, 94, 29, 99, 82, 48, 84]
  排序之后的数组是:[29, 31, 46, 48, 64, 82, 84, 94, 99]
计数排序:
  排序之前的数组是:[11, 20, 56, 2, 47, 75, 66, 21, 3, 74]
  排序之后的数组是:[2, 3, 11, 20, 21, 47, 56, 66, 74, 75]
基数排序:
  排序之前的数组是:[54920007, 10744441, 24003637, 22072166, 12466348, 17322066, 54489715, 64847150, 48366735, 80287146, 71463179, 82992316, 74996232, 37427568, 45629716, 71177033, 81944062, 74519384, 91743758, 68246062, 23798432, 96894141, 69555229, 49967525, 52587116, 43508294, 47269398, 97352691, 82058781, 67895293, 11909501, 30869797, 47345049, 50743493, 25530908, 85030153, 16247011, 76036389, 10846207, 88061686, 17767234, 25997527, 98880748, 26860131, 98633987, 88621984, 89076873, 70419980, 95812196, 21624491]
  排序之后的数组是:[10744441, 10846207, 11909501, 12466348, 16247011, 17322066, 17767234, 21624491, 22072166, 23798432, 24003637, 25530908, 25997527, 26860131, 30869797, 37427568, 43508294, 45629716, 47269398, 47345049, 48366735, 49967525, 50743493, 52587116, 54489715, 54920007, 64847150, 67895293, 68246062, 69555229, 70419980, 71177033, 71463179, 74519384, 74996232, 76036389, 80287146, 81944062, 82058781, 82992316, 85030153, 88061686, 88621984, 89076873, 91743758, 95812196, 96894141, 97352691, 98633987, 98880748]

8种排序算法代码:https://github.com/lijialin0903/sort.git

猜你喜欢

转载自blog.csdn.net/Kirito19970409/article/details/83588757