到目前为止,我们已经知道了时间复杂度O(n^2) 的排序算法:冒泡排序、插入排序、选择排序;还知道了时间复杂度是O(nlogn) 排序算法:归并排序、快速排序。
事实上归并排序、快速排序算法已经可以满足我们大多数的排序需求场景了。还有那么一种场景,我们来假设一下: 某一个社区,有100万人口,我们需要按照年龄大小进行排序,统计该社区的人口年龄分布。这里抓一下关键: 给100万人排序,实际中可能是1000万,或者说以亿为单位的数据量进行排序。
你有想到了什么吗?就是待排序的数据量太大,那么不管是时间复杂度O(n^2) 的排序算法,还是说时间复杂度O(nlogn) 的排序算法,都显得不够高效。有没有更高效的排序算法呢?
答案是:有。它就是我们今天的主角:桶排序
#考考你:
1.你知道桶排序适合的业务场景,以及实现思想吗
2.你能用java实现桶排序吗
案例
桶排序实现思想
关于桶排序,它适合的业务场景,我们记住一句话就够了:数据量大、数据分布相对均匀。
我们举一个例子:
1.给100万用户,按照年龄进行排序,年龄取值范围:0-120
2.满足业务场景,数据量大:100万;数据分布均匀:年龄取值范围0-120岁
实现思想:
1.根据数据取值范围,划分桶: 比如把0-10岁、11-20岁、21-30岁...依次分桶
2.分桶以后,保证桶之间有序。这里按照年龄范围分桶,保证桶之间有序
3.在每个桶内,通过快速排序算法,进行排序
4.最终按照桶顺序进行访问,得到排好序的数据
5.桶排序是一个高效的排序算法,它的时间复杂度是:O(n)
桶排序代码实现
主体代码
package com.anan.algorithm.sort;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 桶排序:
* */
public class BucketSort {
public static void main(String[] args) {
// 1.定义待排序数组
Integer[] array = {1,6,3,4,2,5,9,8,10,7,11,20,17,16,15,18,19,2,3,1,9,8,6};
int n = array.length;
System.out.println("1.待排序数组:" + Arrays.asList(array));
// 2.分两个桶,桶1:1-10岁,桶2:11-20岁
System.out.println("1.数组元素最小值:1,最大值:20,分两个桶:bucket_1,bucket_2");
ArrayList<Integer> bucket_1 = new ArrayList<Integer>(10);
ArrayList<Integer> bucket_2 = new ArrayList<Integer>(10);
// 将array数组的数据,分别填充到桶中
for(int i = 0; i < n; i++){
if(array[i] >=1 && array[i] <= 10){
bucket_1.add(array[i]);
}else{
bucket_2.add(array[i]);
}
}
// 打印分桶后的数据
System.out.println("--------------------------华丽丽分割线------------------------------");
System.out.println("2.排序前,桶bucket_1的大小:" + bucket_1.size() + ",元素内容:" + bucket_1);
System.out.println("3.排序前,桶bucket_2的大小:" + bucket_2.size() + ",元素内容:" + bucket_2);
// 3.通过快速排序,给每个桶排序
System.out.println("--------------------------华丽丽分割线------------------------------");
System.out.println("4.在每一个桶内进行快速排序:");
sort(bucket_1);
sort(bucket_2);
// 打印分桶排序后的数据
System.out.println("5.排序后,桶bucket_1的大小:" + bucket_1.size() + ",元素内容:" + bucket_1);
System.out.println("6.排序后,桶bucket_2的大小:" + bucket_2.size() + ",元素内容:" + bucket_2);
}
}
快速排序部分代码
排序入口
/**
* 排序入口方法
* @param list
*/
public static void sort(ArrayList<Integer> list){
// 如果数据规模小于等于1,则不需要排序
if(list == null ||
list.size() <=1){
return;
}
// 将list数据拷贝到数组,方便操作
Integer[] array = new Integer[list.size()];
for (int i = 0; i < array.length; i++) {
array[i] = list.get(i);
}
// 开始快速排序
quickSort(array,0,array.length - 1);
// 清空原list数据,再把排好序的结果数据拷贝回list
list.clear();
for (int i = 0; i < array.length; i++) {
list.add(array[i]);
}
}
快速排序主体代码
/**
* 快速排序
* @param array
* @param low
* @param high
*/
public static void quickSort(Integer[] array,int low,int high){
// 终止条件
if(low >= high){
return;
}
// 分区函数寻找pivot
int mid = partition(array,low,high);
// 低位递归排序
quickSort(array,low,mid-1);
// 高位递归排序
quickSort(array,mid+1,high);
}
快速排序分区函数:
// 分区函数
public static int partition(Integer[] a,int low,int high){
// 选取第一个元素作为pivot(分区点)
int pivot = a[low];
// 循环处理low<high
while (low < high){
// 从右往左,将小于pivot的数据,放入左边
while(low < high &&
a[high] >= pivot){
high -= 1;
}
a[low] = a[high];
// 从左往右,将大于pivot的数据,放入右边
while(low < high &&
a[low] <= pivot){
low += 1;
}
a[high] = a[low];
}
// 找到分区点
a[low] = pivot;
return low;
}