非基于比较的排序算法
概念&特点
非基于比较的排序与被排序的样本的实际数据状况很有关系,所以实际中并不经常使用;
桶排序就是非基于比较的排序,同时计数排序和基数排序都是属于桶排序;
以上非基于比较的排序算法的时间复杂度O(N),额外空间复杂度O(N)且是稳定的排序 。
桶排序
桶排序:根据被排序的样本的实际数据状况分成n个小区域,每个小区域就是一个桶,最终利用桶来实现排序。例如:现有一些数字在0~99范围内,那么就可以将0~99分成0~9、10~19、20~29…90~99共10个桶,将数据依次填入桶中并保证每个桶中数据有序,最终也就得到了规定的排序。
计数排序
计数排序:计数排序是将桶进一步的细分,实现每个桶只能放相同的数据且桶只负责计数,最终利用桶的计数将全部数据排好序。例如:现有一些数字在0~9范围内,形成0、1、2…9共10个桶,再依次遍历数字对应那个桶就将桶的计数+1,最终就可以根据桶的计数来排序出来。
代码实现如下:
//计数排序(桶排序)算法
// only for 0~200 value
public static void bucketSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
}
int[] bucket = new int[max + 1];
for (int i = 0; i < arr.length; i++) {
bucket[arr[i]]++;
}
int i = 0;
for (int j = 0; j < bucket.length; j++) {
while (bucket[j]-- > 0) {
arr[i++] = j;
}
}
}
基数排序(后续更新)
代码实现如下:
// only for no-negative value
public static void radixSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
radixSort(arr, 0, arr.length - 1, maxbits(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 res = 0;
while (max != 0) {
res++;
max /= 10;
}
return res;
}
public static void radixSort(int[] arr, int begin, int end, int digit) {
final int radix = 10;
int i = 0, j = 0;
int[] count = new int[radix];
int[] bucket = new int[end - begin + 1];
for (int d = 1; d <= digit; d++) {
for (i = 0; i < radix; i++) {
count[i] = 0;
}
for (i = begin; i <= end; i++) {
j = getDigit(arr[i], d);
count[j]++;
}
for (i = 1; i < radix; i++) {
count[i] = count[i] + count[i - 1];
}
for (i = end; i >= begin; i--) {
j = getDigit(arr[i], d);
bucket[count[j] - 1] = arr[i];
count[j]--;
}
for (i = begin, j = 0; i <= end; i++, j++) {
arr[i] = bucket[j];
}
}
}
public static int getDigit(int x, int d) {
return ((x / ((int) Math.pow(10, d - 1))) % 10);
}
补充问题
给定一个数组,求排序之后,相邻两数的最大差值。要求时间复杂度O(N),且要求用非基于比较的排序。
思路:若数组共有N个数据,首先取得数组的取值范围M,将M等分为N+1份。由于有N+1个桶,则N个数据填入桶中后至少有一个桶是空桶,这样的目的是为了排出在桶内出现最大差值,即相邻两数的最大差值只可能在桶之间但并不一定在空桶出现。每个桶中还要给放入桶中的所有数据标识出最大值max与最小值min,最终利用当前桶的min减去前一个桶的max得到最大差值。
代码实现如下:
//排序后相邻最大差值算法
public static int maxGap(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
int len = nums.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < len; i++) {
min = Math.min(min, nums[i]);
max = Math.max(max, nums[i]);
}
if (min == max) {
return 0;
}
//利用hasNum判断桶中是否填入数据;
//maxs记录桶中填入的最大值;
//mins记录桶中填入的最小值。
boolean[] hasNum = new boolean[len + 1];
int[] maxs = new int[len + 1];
int[] mins = new int[len + 1];
int bid = 0;
for (int i = 0; i < len; i++) {
//取得要填入的桶号bid
bid = bucket(nums[i], len, min, max);
mins[bid] = hasNum[bid] ? Math.min(mins[bid], nums[i]) : nums[i];
maxs[bid] = hasNum[bid] ? Math.max(maxs[bid], nums[i]) : nums[i];
hasNum[bid] = true;
}
int res = 0;
int lastMax = maxs[0];
int i = 1;
for (; i <= len; i++) {
if (hasNum[i]) {
res = Math.max(res, mins[i] - lastMax);
lastMax = maxs[i];
}
}
return res;
}
//计算填入的桶号
public static int bucket(long num, long len, long min, long max) {
return (int) ((num - min) * len / (max - min));
}
工程中的综合排序算法
在实际的工程中往往一个排序算法中中会用到多种具体的排序算法,已达到对不同数据的针对性编程,即有些基本类型适合那种算法、有些自定义类型要满足稳定性、有些需要线程安全……这些不同情况下的不同要求就需要我们采用综合排序算法。
举例说明:在Java中的Arrays工具类中sort方法的实现就是采用的综合排序算法。sort针对基本类型(int、double、long等)不需要保证稳定性和数组大小的特点采用插入排序(数组较小)或快排算法(数组较大),而对于自定义的类型则采用归并排序算法与插入排序算法相结合来保证稳定性。后续我将在JavaSE学习笔记中重点介绍Arrays工具类中的常用方法。
我将在java数据结构与算法3---链表、栈与队列(1)中介绍链表、栈与队列。
敬请关注! 点赞+关注不迷路哟!
谢谢阅读 ---by 知飞翀