排序算法-桶排序的时间复杂度分析
Posted talk.push
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法-桶排序的时间复杂度分析相关的知识,希望对你有一定的参考价值。
桶排序思想
桶排序,是一种基于非比较的排序方式,时间复杂度O(n),因此它是是属于一种“线性排序”。
思想:桶排序的思想是将一组数据分到几个有序的桶里,每个桶里的数据再单独进行快速排序。每个桶内都排序完成后,再加上本身桶之间已经是有序的,那么按照桶的顺序依次取出每个桶内的数据,最终组成的序列就是有序的。
桶排序的时间复杂度分析:
假如排序数组的元素个数为n,均匀分布在个数为m的桶中,那么每个桶中的元素个数为k=n/m,因为每个桶快速排序的时间复杂度为klogk即n/mlog(n/m),那么m个桶一起就是nlog(n/m),假如桶的个数m跟元素个数n十分接近,那么最终的时间复杂度为O(n).
如果极端情况下,所有的元素n个都分在一个桶里呢?这种情况下时间复杂度就退化成O(nlogn)了。
所以,可以看出桶排序对数据及其分布的要求是十分苛刻的:
1 要求各个桶之间是有序的,这样每个桶排好序之后,才可以直接根据桶的顺序得到最终排序。
2 每个桶之间数据分布式平均的,如果出现上述极端情况,则时间复杂度就会退化为O(nlogn)了。
代码
package com.study.algorithm.sort;
/**
* @Description:桶排序算法
*/
public class BucketSort
/**
* 桶排序
*
* @param arr 数组
* @param bucketSize 桶容量
*/
public static void bucketSort(int[] arr, int bucketSize)
if (arr.length < 2)
return;
// 数组最小值
int minValue = arr[0];
// 数组最大值
int maxValue = arr[1];
for (int i = 0; i < arr.length; i++)
if (arr[i] < minValue)
minValue = arr[i];
else if (arr[i] > maxValue)
maxValue = arr[i];
// 桶数量
int bucketCount = (maxValue - minValue) / bucketSize + 1;
int[][] buckets = new int[bucketCount][bucketSize];
int[] indexArr = new int[bucketCount];
// 将数组中值分配到各个桶里
for (int i = 0; i < arr.length; i++)
int bucketIndex = (arr[i] - minValue) / bucketSize;
if (indexArr[bucketIndex] == buckets[bucketIndex].length)
ensureCapacity(buckets, bucketIndex);
buckets[bucketIndex][indexArr[bucketIndex]++] = arr[i];
// 对每个桶进行排序,这里使用了快速排序
int k = 0;
for (int i = 0; i < buckets.length; i++)
if (indexArr[i] == 0)
continue;
quickSortC(buckets[i], 0, indexArr[i] - 1);
for (int j = 0; j < indexArr[i]; j++)
arr[k++] = buckets[i][j];
/**
* 数组扩容
*
* @param buckets
* @param bucketIndex
*/
private static void ensureCapacity(int[][] buckets, int bucketIndex)
int[] tempArr = buckets[bucketIndex];
int[] newArr = new int[tempArr.length * 2];
for (int j = 0; j < tempArr.length; j++)
newArr[j] = tempArr[j];
buckets[bucketIndex] = newArr;
/**
* 快速排序递归函数
*
* @param arr
* @param p
* @param r
*/
private static void quickSortC(int[] arr, int p, int r)
if (p >= r)
return;
int q = partition(arr, p, r);
quickSortC(arr, p, q - 1);
quickSortC(arr, q + 1, r);
/**
* 分区函数
*
* @param arr
* @param p
* @param r
* @return 分区点位置
*/
private static int partition(int[] arr, int p, int r)
int pivot = arr[r];
int i = p;
for (int j = p; j < r; j++)
if (arr[j] <= pivot)
swap(arr, i, j);
i++;
swap(arr, i, r);
return i;
/**
* 交换
*
* @param arr
* @param i
* @param j
*/
private static void swap(int[] arr, int i, int j)
if (i == j)
return;
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
桶排序的应用场景
桶排序适合用在外部排序中,就是数据存储在外部磁盘上,由于服务器内存有限无法一次性加载到内存中。
比如现在有10G订单数据存在外部磁盘的一个文件中,我们想将这10G的订单数据按照从小到大进行排序,但是由于服务器内存有限只有几百M,无法一次性加载内存,这时候就可以利用桶排序进行解决了。
思路:
可以先找出这批订单的最大值和最小值,比如扫描一遍文件,最大值是10万,最小值是1元,那么我们可以将这10G的订单分别划分到100个桶中,比如:1元到1000元的放在第一个桶内,1001到2000元的放到第二个桶内,以此类推。每个桶我们最终都会生成一个文件,这个小文件中存放的都是之前划分的那些订单数据,我们进行一个编号,比如(00,01,02,...99).
理想情况:
理想情况下,这10万的订单数据均匀分布到100个桶中,每个桶都存放1000个订单,每个桶即每个子文件大约是存储100M的数据,那么这100个子文件依次加载到内存中进行快速排序,排序完成后。我们依次读取每个子文件的数据并写入到一个大文件中,这样以来这10G的数据就排序完成了。
实际情况:
实际情况是这10G订单数据不可能是均匀分布的,一般人买东西肯定是金额低的多一些,金额高的就很少了,所以每个桶内不可能是很均匀的,这种情况的处理办法就是继续划分这个数据量大的桶为几个子桶,一直到每个桶的数据可以被一次性读入内存为止。
桶排序是稳定的排序算法吗?
由于桶排序是如果基于快排实现,就不是稳定的排序算法。
如果是基于归并排序实现的,则可以完成稳定的排序。
桶排序是原地排序算法吗?
桶排序每个桶需要用到外部存储空间,所以不是原地排序算法。
以上是关于排序算法-桶排序的时间复杂度分析的主要内容,如果未能解决你的问题,请参考以下文章