Java实现计数排序逐步优化

博客介绍了计数排序的基本原理和优化方法,包括从原始实现到改进版的流程,优化主要体现在空间效率的提升。内容还展示了如何将计数排序应用于自定义对象数组的排序,以对象的int类型属性作为排序依据。整个排序过程的时间复杂度为O(n+k),适用于正整数排序或特定属性排序的场景。
摘要由CSDN通过智能技术生成

最朴素的实现

已经有详细注释了,懂的都懂,就是用出现的正整数当做数组索引,然后记录元素出现的次数,最后再将记录出现次数的数组遍历出来存储在结果数组中

缺点显而易见,就是只能给正整数排序,而且及其浪费空间。

protected void sort0() {	//计数排序 最朴素的实现
		// 找出最大值
		int max = array[0];
		for (int i = 1; i < array.length; i++) {
			if (array[i] > max) {
				max = array[i];
			}
		} // O(n)
		
		// 开辟内存空间,存储每个整数出现的次数
		int[] counts = new int[1 + max];
		// 统计每个整数出现的次数
		for (int i = 0; i < array.length; i++) {
			counts[array[i]]++;
		} // O(n)
		
		// 根据整数的出现次数,对整数进行排序
		int index = 0;
		for (int i = 0; i < counts.length; i++) {
			while (counts[i]-- > 0) {
				array[index++] = i;
			}
		} // O(n)
	}

优化后的计数排序

先找出待排序数组的最大值和最小值,然后通过这两个值确定存储出现次数的数组的大小,再遍历原数组,更新counts数组,即更新每个元素出现的次数。记录好之后,再次更新counts数组的每一个值,从1索引位置开始,将每一个元素的值更新为自己和其前面元素值的和。再从后往前遍历原数组,将每一个索引i对应的元素放到newArray数组的- -counts[array[i] - min]索引位置。最后再将有序数组赋值到array

时间复杂度O(n + k),n为数据规模,k为数据范围

protected void sort() {
		// 找出最值 
		int max = array[0];
		int min = array[0];
		for (int i = 1; i < array.length; i++) {
			if (array[i] > max) {					//最大和最小值可能是相同的,所以两个if
				max = array[i];
			}
			if (array[i] < min) {
				min = array[i];
			}
		}
		
		// 开辟内存空间,存储次数
		int[] counts = new int[max - min + 1];
		// 统计每个整数出现的次数
		for (int i = 0; i < array.length; i++) {
			counts[array[i] - min]++;			//优化后,array[i] - min就是array[i]这个元素在counts数组的索引
		}
		// 累加次数
		for (int i = 1; i < counts.length; i++) {
			counts[i] += counts[i - 1];
		}
		
		// 从后往前遍历元素,将它放到有序数组中的合适位置
		int[] newArray = new int[array.length];
		for (int i = array.length - 1; i >= 0; i--) {
			//--counts[array[i] - min],counts[array[i] - min]为当前元素的出现次数,减1即为应存储在新数组中的索引,存储后同时出现次数也减1
			newArray[--counts[array[i] - min]] = array[i];
		}
		
		// 将有序数组赋值到array
		for (int i = 0; i < newArray.length; i++) {
			array[i] = newArray[i];
		}
	}

优化后的计数排序可以排序自定义对象类型,即排序自定义对象数组,自定义对象的int类型的属性作为排序的根据

public static void main(String[] args) {
		Person[] persons = new Person[] {
				new Person(20, "A"),
				new Person(-13, "B"),
				new Person(17, "C"),
				new Person(12, "D"),
				new Person(-13, "E"),
				new Person(20, "F")
		};
		
		// 找出最值
		int max = persons[0].age;
		int min = persons[0].age;
		for (int i = 1; i < persons.length; i++) {
			if (persons[i].age > max) {
				max = persons[i].age;
			}
			if (persons[i].age < min) {
				min = persons[i].age;
			}
		}
		
		// 开辟内存空间,存储次数
		int[] counts = new int[max - min + 1];
		// 统计每个整数出现的次数
		for (int i = 0; i < persons.length; i++) {
			counts[persons[i].age - min]++;
		}
		// 累加次数
		for (int i = 1; i < counts.length; i++) {
			counts[i] += counts[i - 1];
		}
		
		// 从后往前遍历元素,将它放到有序数组中的合适位置
		Person[] newArray = new Person[persons.length];
		for (int i = persons.length - 1; i >= 0; i--) {
			newArray[--counts[persons[i].age - min]] = persons[i];
		}
		
		// 将有序数组赋值到array
		for (int i = 0; i < newArray.length; i++) {
			persons[i] = newArray[i];
		}
		
		for (int i = 0; i < persons.length; i++) {
			System.out.println(persons[i]);
		}
	}
	
	private static class Person {
		int age;
		String name;
		Person(int age, String name) {
			this.age = age;
			this.name = name;
		}
		@Override
		public String toString() {
			return "Person [age=" + age 
					+ ", name=" + name + "]";
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值