排序
序言
排序是非常基础并且重要的算法,目前常见的排序算法有插入排序
、冒泡排序
、堆排序
、计数排序
、归并排序
和快速排序
等。
计数排序
计数排序是一种线性时间的整数排序算法。如果数组的长度为
n
,整数范围(数组中最大值和最小值的差值)为K,若k远小于n,则计数排序的时间效率会远小于插入、归并排序等。如对公司员工的年龄进行排序,就可以考虑计数排序。
排序思想
统计数组中每个数字出现的次数,然后按照数字从小到大的顺序依次填充到数组中去。
- 比如数组[2 , 3 , 4 , 2 , 3 , 2 , 1 ],可以计算出差值
k
为3; - 此时我们准备一个容量为
4(k+1)
的数组Array,在对应数组的位置存放每个值出现的次数。比如值2则存放到位置1,值3则存放到位置2,值4则存放到位置3,值1则是位置0; - 最终Array会变成这个样子[1 , 3 , 2 , 1],代表1出现了1次,2出现了3次,3出现了2两次,4出现了1次。
- 依次读取Array数组,即可知道排序结果[1 , 2 , 2 , 2 , 3 , 3 , 4]。
代码实现
fun countSortArray(array: IntArray) {
//获取最大值和最小值
var maxValue = Int.MIN_VALUE
var minValue = Int.MAX_VALUE
array.forEach {
maxValue = Math.max(maxValue, it)
minValue = Math.min(minValue, it)
}
//利用最大值和最小值准备空数组 , 并且存放对应值的出现的次数
val snapArray = IntArray(maxValue - minValue + 1)
array.forEach {
val index = it - minValue
val snapCount = snapArray[index]
snapArray[index] = snapCount + 1
}
//依次读取数组,进行值排序
var index = 0
for (i in snapArray.indices) {
val value = snapArray[i]
var count = value
while (count > 0) {
array[index++] = i + minValue
count--
}
}
}
时间复杂度:数组的长度为n,整数范围为k,所以时间复杂度为O(n+k)。
空间复杂度:需要创建一个长度为(k+1)的数组进行辅助,所以控件复杂度为O(K)。
示例
存在两个数组arr1
和arr2
,arr2
中的每一个数组都唯一且是arr1
中的数字。要求arr1
中的数字要按照arr2
进行相对排序。如果数组arr1
中存在arr2
中没有的数字,则按照递增的顺序排在后面。设定数组中的数字均在1000范围内。
列如:arr1
是[2 , 3 , 3 , 7 , 3 , 9 , 2 , 1 , 7 , 2],arr2
是[3 , 2 , 1]。则排序的结果为[3 , 3 , 3 , 2 , 2 , 2 , 1 , 7 , 9]。
分析:1000范围内,所以k即为1000,考虑计数排序。之后现根据数组arr2
输出,然后按照大小输出。
fun countSortArrayQuestion(array1: IntArray, array2: IntArray) {
//根据差值 计算每个数字出现的频率
val diffValue = 1000
val snapArray = IntArray(diffValue + 1)
array1.forEach {
val index = it
val snapCount = snapArray[index]
snapArray[index] = snapCount + 1
}
var index = 0
//首先排序arr2中存在的
array2.forEach {
val value = snapArray[it]
var count = value
while (count > 0) {
array1[index++] = it
count--
}
//清空
snapArray[it] = 0
}
//剩余排序
for (i in snapArray.indices) {
val value = snapArray[i]
var count = value
while (count > 0) {
array1[index++] = i
count--
}
}
}
🙆♀️。欢迎技术探讨噢!