算法学习篇——桶排序的实现

桶排序的介绍

原理: 将数据分配到多个桶中,对每个桶单独排序,最后合并。
时间复杂度:
最好情况: O ( n + k ) O(n + k) O(n+k) (k 是桶的数量)
最坏情况: O ( n 2 ) O(n²) O(n2) (所有数据集中在同一个桶中,退化成插入排序)
平均情况: O ( n + k ) O(n + k) O(n+k)
空间复杂度: O ( n + k ) O(n + k) O(n+k)
稳定性: 稳定
适用场景: 数据分布均匀的情况。

桶排序原始数据
桶排序原始数组数据

桶排序排序中
在这里插入图片描述

实现桶排序

桶排序的实现是基于数组+链表的数据结构。其中关键点有4个

  • 桶的个数=数组的长度
  • 桶的下标用hash算出,公式为 element × length max + 1 \frac{\text{element} \times \text{length}}{\text{max} + 1} max+1element×length,其中element表示元素实际的值,length表示数组的长度,max表示数组中最大的元素值
  • 当发生哈希冲突时,发生冲突的数据会进行进行局部并组成一个链表。这里会涉及到单链表的插入
  • 当元素完成在桶中的插入及排序之后,需要遍历桶对应的链表,依次出桶,放入原数组。
  // 根据桶的个数来确定hash函数,这份代码适合桶的个数等于数组长度
  private static int hash(int element, int max, int length) {
    return (element * length) / (max + 1);
  }

  public static void main(String[] args) {
    int[] arr = Util.getRandomArr( 10, 1, 100 );
    System.out.println( "begin..." + Arrays.toString( arr ) );
    new _9BucketSort().sort( arr );
    System.out.println( "final..." + Arrays.toString( arr ) );
    Assertions.assertThat( Util.checkOrdered( arr, true ) ).isTrue();
  }

  private void sort(int[] arr) {
    int length = arr.length;
    LinkedNode[] bucket = new LinkedNode[length];  // 桶的个数=length
    int max = Util.maxOf(arr);//求max
    // 入桶
    for (int i = 0; i < length; i++) {
      int value = arr[i];//扫描每个元素
      int hash = hash( arr[i], max, length ); // 桶的下标
      if (bucket[hash] == null) {
        bucket[hash] = new LinkedNode( value ); // 初始化链表表头
      } else {
        insertInto( value, bucket[hash], bucket, hash ); // 插入链表
      }
    }

    int k = 0; // 记录数组下标
    //出桶,回填arr
    for (LinkedNode node : bucket) {
      if (node != null) {
        while (node != null) {
          arr[k++] = node.value;
          node = node.next;
        }
      }
    }
  }

  private void insertInto(int value, LinkedNode head, LinkedNode[] bucket, int hash) {
    LinkedNode newNode = new LinkedNode( value );
    //小于头节点,放在头上
    if (value <= head.value) {
      newNode.next = head;
      // 替换头节点
      bucket[hash] = newNode;
      return;
    }
    /*往后找第一个比当前值大的节点,放在这个节点的前面*/
    LinkedNode p = head;
    LinkedNode pre = p;
    while (p != null && value > p.value) {
      pre = p;
      p = p.next;
    }
    if (p == null) { // 跑到末尾了
      pre.next = newNode;
    } else { // 插入pre和p之间
      pre.next = newNode;
      newNode.next = p;
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值