排序算法——桶排序

简单桶排序

简单桶排序又称为鸽巢排序计数排序,其基本思想如下:

假设待排序整型数组arr的元素大小范围是[0, max],

额外分配一个长度为(max+1)的整型数组bucket[max+1],数组中元素初始全部初始化为0,

那么每一个bucket数组中元素就相当于一个(或称为鸽巢),元素的下标相当于这个桶所要装的数值的大小,元素的值代表有多少个这个大小的值

遍历arr,假设当前元素arr[i]的值是x,那么bucket数组中下标为x的元素加1(相当于在放大小是x的桶中放入了一个元素),如此类推,直到arr遍历完成,(此时可理解为arr已清空,但数组还在),

最后,遍历bucket数组,当遍历到元素不为0的元素时,将该元素下标从头赋值到arr中,该元素的值是几就赋值几次,直到bucket遍历完成,

此时arr数组已成为有序数组。

如下图:

 

Java代码实现:

 1 /**
 2  * 用简单桶排序算法对整型数组进行升序排序
 3  *
 4  * @param arr:待排序数组
 5  * @param maxVal:待排序数组中元素的最大值
 6  */
 7 private static void simpleBucketSort(int[] arr, int maxVal) {
 8     if (arr == null || arr.length <= 1)
 9         return;
10     //分配桶数组
11     int[] bucket = new int[maxVal + 1];
12     //装桶
13     for (int i = 0; i < arr.length; i++) {
14         if (arr[i] < 0)
15             throw new RuntimeException("待排序数组中包含负数!");
16         bucket[arr[i]]++;
17     }
18     //将桶中元素依次放回原数组
19     int index = 0;
20     for (int i = 0; i < bucket.length; i++) {
21         for (int j = 0; j < bucket[i]; j++)
22             arr[index++] = i;
23     }
24 }

  

特点:

1. 简单桶排序的时间复杂度是O(N),而且它完全没有比较操作,所以效率非常高。

2. 由于需要开辟新数组(桶),所以其空间复杂度非常高,其最坏空间复杂度为O(N2。若待排序数组元素大小的范围非常大,则对空间的占用会更高。

2. 显而易见,简单桶排序的局限性非常大。首先,必须知道待排序数组元素的范围,否则无法进行。其次若待排序数组非整数负数,同样无法操作。

 

真正的桶排序

基本思想:

把待排序数组划分为n个大小相同子区间(桶),每个子区间各自排序,最后合并 。

可见,简单桶排序是桶排序的一个特例,相当于子区间内只有一个数的桶排序。

但桶排序要求数据的分布必须均匀,否则可能所有数据都集中到一个子区间中,导致桶排序失去意义。

 

Java代码实现:

 1 /**
 2  * 用桶排序算法对整型数组进行升序排序
 3  *
 4  * @param arr:待排序数组
 5  */
 6 private static void bucketSort(int[] arr) {
 7     /*找出数组中的最大值和最小值*/
 8     int max = Integer.MIN_VALUE;
 9     int min = Integer.MAX_VALUE;
10     for (int i = 0; i < arr.length; i++) {
11         max = Math.max(max, arr[i]);
12         min = Math.min(min, arr[i]);
13     }
14 
15     /*分配桶*/
16     int nBucket = (max - min) / arr.length + 1; //桶的个数
17     List<List<Integer>> buckets = new ArrayList<>(nBucket); //用线性表作为桶,桶内的数据结构也是线性表
18     for (int i = 0; i < nBucket; i++)
19         buckets.add(new ArrayList<>());
20 
21     /*将元素放入桶中*/
22     for (int i = 0; i < arr.length; i++) {
23         int n = (arr[i] - min) / arr.length; //找到对应的桶号
24         buckets.get(n).add(arr[i]); //放入对应桶号的桶中
25     }
26 
27     /*用其它算法对每个桶中的元素进行排序*/
28     for (int i = 0; i < nBucket; i++)
29         Collections.sort(buckets.get(i)); //此处用API模拟使用了其它算法
30 
31     /*将排序后的元素放回原数组中*/
32     int index = 0;
33     for (List<Integer> bucket : buckets)
34         for (Integer i : bucket)
35             arr[index++] = i;
36 }

 此处用线性表作为桶内的数据结构,解决了简单桶排序中,元素不能存在负数的问题。

 

典型应用:

1. 全国高考分数排序。高考分数为0~750,没有小数,假设全国500万考生。显然数值范围已知,数据量庞大,桶排序是一个很好的解决方法。

2. 大文件快速排序。(以后另起一篇文章探讨这个话题)

 

转载于:https://www.cnblogs.com/lwfung/p/7514895.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值