桶排序算法
定义:
工作的原理是将数组分到有限数量的桶子里。每个桶子再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)
桶排序是一种非基于比较的排序
算法步骤:
- 首先各个元素就可以直接通过整除的方法放至对应桶中,此时右侧所有桶内数据都比左侧的要大
- 在刚刚放入桶中的时候,各个桶的大小相对可以确定,右侧都比左侧大,但桶内还是无序的,对各个桶内分别进行排序,
- 再依次按照桶间的顺序、桶内序列顺序依次收集,得到一个最终排序的序列。
性能
时间复杂度(说法一,仅仅适用于本blog中的代码):时间复杂度最好可能是线性O(n),O(d * (n + k)),其中k表示桶的数量,n表示数组的大小,d表示序列中最大值的位数,即收集的轮次
空间复杂度:O(N + M),N为临时数组,与待排序列的长度相等,M为桶的数量
另有关于基数排序的时间复杂度公式请查看末尾的链接。
稳定性:桶排序的稳定性取决于桶内排序使用的算法。本blog中的代码使用到的桶内排序的算法是稳定的
实现代码(简单易懂版)
package basic;
import static basic.Insertion_sort.print;
public class Radix_sort {
public static void main(String[] args) {
int []arr = {50, 11, 200, 20, 15, 17, 23, 10, 500, 66, 23, 98};
radix_sort(arr, 0, arr.length - 1, maxBits(arr));
print(arr);
}
// 返回一个数组中的最大值是由几个数字组成的
public static int maxBits(int arr[])
{
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++)
max = Math.max(max, arr[i]);
int bits = 0;
while (max !=0)
{
bits++;
max /= 10;
}
return bits;
}
// 获取val上第d位(从右往左数)的数字
public static int getDigit(int val, int d)
{
return (val / ((int)Math.pow(10, d - 1))) % 10;
}
public static void radix_sort(int[] arr, int L, int R, int digit)
{
int i =0, j = 0;
// 有多少个数就准备多少个桶空间
int[] buckets = new int[R - L + 1];
// digit是序列中最大值的位数
for (int d = 1; d <= digit; d++)
{
// 使用10个桶,分别代表0 - 9这9个数字
int[] counts = new int[10];
// 第一步先统计词频
for (j = L; j <= R; j++)
counts[getDigit(arr[j], d)]++;
// 第二步,累加词频
// counts[0]表明当前位(d位)是0的数字有多少个
for (j = 1; j < 10; j++)
counts[j] += counts[j - 1];
// 出桶,并且将该轮次整理好的数列放到临时数组中
// 之所以从右到左收集,是为了保证稳定性不被破坏,即符合桶内队列的性质,后进后出
for (j = R; j >= L; j--)
{
// 获取arr[j]的第d位数字
int number = getDigit(arr[j], d);
// 出桶的过程,即将对应的数放到最终合适的位置上
buckets[counts[number] - 1] = arr[j];
// 对应digit上的词频减1,表示出桶完毕
counts[number]--;
}
// 将临时数组中的数据放到arr中,以便进行下一轮的入桶操作
for (i = L, j =0; i <= R; j++, i++)
arr[i] = buckets[j];
}
}
}
这篇博客讲解的比较详细,建议点击此链接