数据结构:排序—计数,桶,基数排序(五)

目录

一、计数排序

二、桶排序

三、基数排序


一、计数排序

基本思路:计数排序是不基于比较的排序方法,他是按照找出所排序序列的最大值和最小值,并且根据最大值和最小值的差值开辟一个数组:max-min+1。

然后,遍历待排序数组,将得到的值作为新数组的下标,我们每得到一个数就再让新数组这个数所对应的下标处的值加1。这样就知道了对应位置有多少的相同元素。

之后,我们遍历新数组,得到新数组的值,同时从头根据新数组的下标值依次更新原数组的值,这样我们就得到了我们升序的数据(如果是相同的元素需要根据新数组的值存放,每存放一个就将新数组的值减一,直到值为0,同理如果只有一个元素(没有相同的元素)值就为1,存放后也会等于0)。

注意:我们还有一点需要注意,如果我们要排序的数据0-9,我们创建的数组就是0-9的数组,但如果我们排序的是90-99的数,我们还是会创建0-9的数组,但这样我们就没有办法存储数据了,因此我们需要对他进行改进,那么我们该怎么做呢?

我们可以在取得原数组的值时,让他减去我们的最小值,像我们的90-90=0,91-90=1,这样我们就能存进数组里了。

但是,我们由于将他减去了最小值,但是我们在更新数组的时候,我们更新的值是我们新数组的下标,所以我们在更新的时候要加上最小值。

java 复制代码
public static void countSort(int[] arr){
        int min = arr[0];
        int max = arr[0];
        for(int i = 1;i<arr.length;i++){
            if(arr[i] < min){
                min = arr[i];
            }
            if(arr[i] > max){
                max = arr[i];
            }
        }
        int len = max-min+1;
        int[] countArr = new int[len];
        for(int i = 0;i<arr.length;i++){
            int index = arr[i]-min;
            countArr[index]++;
        }
        int k = 0;
        for (int i = 0; i < len; i++) {
            while(countArr[i] != 0){
                arr[k] = i+min;
                k++;
                countArr[i]--;
            }
        }
    }

二、桶排序

基本思路:桶排序是计数排序的延申,计数排序是可以看成每个相同的元素放入同一个桶中,而桶排序是将同一个范围的元素放入同一个桶中,然后排序每个桶中的元素,最后将不是空桶的桶中元素按照桶的顺序依次放回原数组中。

首先,我们还是求出最大值和最小值,根据他们的差值求出每个桶的范围大小:size = (mx - mn) / n + 1,n为数据的个数,需要保证至少有一个桶,故而需要加个1;(从最小值开始加上size就是第一个桶的范围,且范围为左闭右开)

之后,我们要根据桶的范围大小,求出桶的个数:cnt = (mx - mn) / size + 1,需要保证每个桶至少要能装1个数,故而需要加个1;

最后,我们要根据我们遍历到是数据求它应该在的桶编号:idx = (nums[i] - mn) / size。

java 复制代码
 //桶排序
    public static void bucketSort(int[] nums) {
        int n = nums.length;
        int mn = nums[0], mx = nums[0];
        // 找出数组中的最大最小值
        for (int i = 1; i < n; i++) {
            mn = Math.min(mn, nums[i]);
            mx = Math.max(mx, nums[i]);
        }
        int size = (mx - mn) / n + 1; // 每个桶存储数的范围大小,使得数尽量均匀地分布在各个桶中,保证最少存储一个
        int cnt = (mx - mn) / size + 1; // 桶的个数,保证桶的个数至少为1
        List<Integer>[] buckets = new List[cnt]; // 声明cnt个桶
        for (int i = 0; i < cnt; i++) {
            buckets[i] = new ArrayList<>();//创建桶
        }
        // 扫描一遍数组,将数放进桶里
        for (int i = 0; i < n; i++) {
            int idx = (nums[i] - mn) / size;//判断元素属于那个编号的桶中
            buckets[idx].add(nums[i]);
        }
        // 对各个桶中的数进行排序,这里用库函数快速排序
        for (int i = 0; i < cnt; i++) {
            buckets[i].sort(null); // 默认是按从小到大到排序
        }
        // 依次将各个桶中的数据放入返回数组中
        int index = 0;
        for (int i = 0; i < cnt; i++) {
            for (int j = 0; j < buckets[i].size(); j++) {
                nums[index++] = buckets[i].get(j);
            }
        }
    }

三、基数排序

基本思路:基数排序又是桶排序的延申,我们以整数为例,准备10个桶代表0-9,我们从整数的个位开始将对应的值放入对应编号的桶中,之后再将他们按照桶的顺序放回到原数组中,然后在从十位开始排,放入对应编号的桶中和放回到原数组中,之后从百位开始排,放入对应编号的桶中和放回到原数组中,如果对应的数没有百或十位数,就将他放到0号桶中。

最后当所有数的位都找完了后就代表我们已经将他排好序了。

java 复制代码
// 基数排序
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);
}

好了,今天的分享就到这里了,还请大家多多关注我们下一篇见!

相关推荐
uhakadotcom9 分钟前
NVIDIA Resiliency Extension(NVRx)简介:提高PyTorch训练的容错性
算法·面试·github
雷渊26 分钟前
深入分析mybatis中#{}和${}的区别
java·后端·面试
梭七y27 分钟前
【力扣hot100题】(020)搜索二维矩阵Ⅱ
算法·leetcode·职场和发展
亦是远方32 分钟前
2025华为软件精英挑战赛2600w思路分享
android·java·华为
v维焓38 分钟前
C++(思维导图更新)
开发语言·c++·算法
花月C1 小时前
Spring IOC:容器管理与依赖注入秘籍
java·开发语言·rpc
ylfhpy1 小时前
Java面试黄金宝典22
java·开发语言·算法·面试·职场和发展
Phoebe鑫1 小时前
数据结构每日一题day9(顺序表)★★★★★
数据结构·算法
烁3471 小时前
每日一题(小白)动态规划篇2
算法·动态规划
风象南1 小时前
Spring Boot 实现文件秒传功能
java·spring boot·后端