非比较排序-计数排序、桶排序、基数排序(java实现)


活动地址:CSDN21天学习挑战赛

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…

在之前学习的冒泡、选择、插入、归并、快速、希尔、堆排序,都是基于比较的排序,所以平均时间复杂度目前最低是 O(nlogn),但由于计数排序、桶排序、基数排序,都不是基于比较的排序,它们是典型的用空间换时间,在某些时候,平均时间复杂度可以比 O nlogn 更低。

1.计数排序

计数排序于1954年由Harold H. Seward提出,适合对一定范围内的整数进行排序
◼ 计数排序的核心思想
统计每个整数在序列中出现的次数,进而推导出每个整数在有序序列中的索引
实现如下
◼ 最好、最坏、平均时间复杂度:O(n + k)
◼ 空间复杂度:O(n + k)
◼ k 是整数的取值范围
◼ 属于稳定排序

 protected void sort() {
     // 获取列表最大最小值
     int min = 0;
     int max = 0;
     for (int i = 1; i < data.length; i++) {
         if (data[i] > max) {
             max = data[i];
         }
         if (data[i] < min) {
             min = data[i];
         }
     }
     // 创建元素数量数组
     int[] counts = new int[max - min + 1];
     for (int i = 0; i < data.length; i++) {
         counts[data[i] - min]++;
     }
     // 转换为元素位置数组
     for (int i = 1; i < counts.length; i++) {
         counts[i] += counts[i - 1];
     }
     // 创建临时数组,存放元素
     Integer[] tmp = new Integer[data.length];
     for (int i = data.length - 1; i >= 0; i--) {
         tmp[--counts[data[i]]] = data[i];
     }
     System.arraycopy(tmp, 0, data, 0 ,data.length);
 }

2.基数排序

基数排序非常适合用于整数排序(尤其是非负整数),因此本课程只演示对非负整数进行基数排序
◼ 执行流程:依次对个位数、十位数、百位数、千位数、万位数…进行排序(从低位到高位)
◼ 最好、最坏、平均时间复杂度:O(d ∗ (n + k)) ,d 是最大值的位数,k 是进制。属于稳定排序
◼ 空间复杂度:O(n + k),k 是进制
实现如下

  protected void sort() {
      int max = 0;
      for (int tmp : data) {
          if (tmp > max) {
              max = tmp;
          }
      }
      for (int digit = 1; digit <= max; digit *= 10) {
          radixSort(digit);
      }
  }

  /**
   * 对digit(1,10,100...)为进行排序
   */
  private void radixSort(int digit) {
      int[] counts = new int[10];
      // 因为每一位的范围在0~9,范围较小适合计数排序
      for (int tmp : data) {
          counts[(tmp / digit) % 10]++;
      }
      for (int cur = 1; cur < counts.length; cur++) {
          counts[cur]+=counts[cur - 1];
      }
      Integer[] tmp = new Integer[data.length];
      for (int cur = data.length - 1; cur >=0 ;cur--) {
          tmp[--counts[(data[cur] / digit) % 10]] = data[cur];
      }
      System.arraycopy(tmp, 0, data, 0 , data.length);
  }

3.桶排序

桶排序是将待排序集合中处于同一个值域的元素存入同一个桶中,也就是根据元素值特性将集合拆分为多个区域,则拆分后形成的多个桶,从值域上看是处于有序状态的。对每个桶中元素进行排序,则所有桶中元素构成的集合是已排序的。

执行流程

① 创建一定数量的桶(比如用数组、链表作为桶)
② 按照一定的规则(不同类型的数据,规则不同),将序列中的元素均匀分配到对应的桶
③ 分别对每个桶进行单独排序
④ 将所有非空桶的元素合并成有序序列
◼ 空间复杂度:O(n + m),m 是桶的数量
◼ 时间复杂度:O n + k ,k 为 n ∗ logn − n ∗ logm
属于稳定排序

实现如下

  /**
   * 子类需要实现的核心排序算法
   */

  protected void sort() {
      // 对 [0,1)的浮点数进行排序
      // 创建data.length个桶
      int bucketSize = data.length;
      List<Double>[] buckets = new List[bucketSize];
      // 向桶中存放元素
      for (int cur = 0; cur < data.length; cur++) {
          int pos = (int) (data[cur] * bucketSize);
          if (buckets[pos] == null) {
              buckets[pos] = new LinkedList<>();
          }
          buckets[pos].add(data[cur]);
      }
      int index = 0;
      // 对桶内元素进行排序
      for (int cur = 0; cur < bucketSize; cur++) {
          if (buckets[cur] != null) {
              buckets[cur].sort(null);
              for (Double tmp : buckets[cur]) {
                  data[index++] = tmp;
              }
          }
      }
  }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值