桶排序
首先讨论的问题:给定一个数组,求如果排序后,相邻两数的最大值,要求时间复杂度 O(n)?
桶:数组长度N,设计一个桶,数量为(N+1)个桶,数组最小值放进第一个桶,数组最大值放进最后一个桶,每一个桶都要包含min,max,这两个边界值。所以中间一定存在一个空桶,那么就可以得到一个结论:桶内之间绝对不会存在最大差值,最大差值就一定在桶与桶的边界值之间。从第二个桶开始遍历,用这个桶的min减去前一个非空桶的max得到差值,那么整个数组相邻的最大差值一定在这里面。
#include <stdio.h>
//根据要入桶的数和最大最小值得到对应桶编号
int getBucketId(int num,int bucketsNum,int min,int max){
return (num - min) * bucketsNum / (max - min);
}
int max(int a, int b){
return a > b ? a : b;
}
int min(int a, int b){
return a < b ? a : b;
}
int getMaxGap(int arr[], int length) {
if (arr == NULL || length < 2) {
return -1;
}
int maxValue = -999999, minValue = 999999;
int i;
//找出最大最小值
for (i = 0; i < length; ++i) {
maxValue = max(maxValue, arr[i]);
minValue = min(minValue, arr[i]);
}
//记录每个桶的最大最小值以及是否有数,初始时每个桶都没数
int maxs[length + 1], mins[length + 1];
bool hasNum[length + 1];
for (i = 0; i < length + 1; i++) {
hasNum[i] = false;
}
//put maxValue into the last bucket
mins[length] = maxs[length] = maxValue;
hasNum[length] = true;
//iterate the arr
int bid; //bucket id
for (i = 0; i < length; i++) {
if (arr[i] != maxValue) {
bid = getBucketId(arr[i], length + 1, minValue, maxValue);
//如果桶里没数,则该数入桶后,最大最小值都是它,否则更新最大最小值
mins[bid] = !hasNum[bid] ? arr[i] : arr[i] < mins[bid] ? arr[i] : mins[bid];
maxs[bid] = !hasNum[bid] ? arr[i] : arr[i] > maxs[bid] ? arr[i] : maxs[bid];
hasNum[bid] = true;
}
}
//find the max gap between two nonEmpty buckets
int res = 0, j = 0;
for (i = 0; i < length; ++i) {
j = i + 1;//the next nonEmtpy bucket id
while (!hasNum[j]) {//the last bucket must has number
j++;
}
res = max(res, (mins[j] - maxs[i]));
}
return res;
}
int main(){
int arr[] = {13, 41, 67, 26, 55, 99, 2, 82, 39, 100};
printf("%d", getMaxGap(arr, 9)); //17
return 0;
}
理解了上述代码的话,桶排序就很简单了,就是计数排序,统计一个数出现了多少次,然后重新打印会数组。但是局限于要排序的数组max值很小。否则数组开销代价太大。桶排序是非比较的,是统计的。
package 左神_算法;
import java.util.Arrays;
public class BucketSort {
/**
* 桶排序
* 1,非基于比较的排序,与被排序的样本的实际数据状况很有关系,所
以实际中并不经常使用
* 2,时间复杂度O(N),额外空间复杂度O(N)
* 3,稳定的排序
*
*/
// 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]; // 定义一个可以容纳数组里面的max+1个数
for (int i = 0; i < arr.length; i++) { // 把arr的值映射进数组里面,记录有多少个
bucket[arr[i]]++;
}
int i = 0;
for (int j = 0; j < bucket.length; j++) { //把桶里面的值,重新输入到arr中
while (bucket[j]-- > 0) {
arr[i++] = j;
}
}
}
// for test
public static void comparator(int[] arr) {
Arrays.sort(arr);
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random());
}
return arr;
}
// for test
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
// for test
public static boolean isEqual(int[] arr1, int[] arr2) {
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
return false;
}
if (arr1 == null && arr2 == null) {
return true;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
// for test
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// for test
public static void main(String[] args) {
int testTime = 500000;
int maxSize = 100;
int maxValue = 150;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
bucketSort(arr1);
comparator(arr2);
if (!isEqual(arr1, arr2)) {
succeed = false;
printArray(arr1);
printArray(arr2);
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
int[] arr = generateRandomArray(maxSize, maxValue);
printArray(arr);
bucketSort(arr);
printArray(arr);
}
}