计数排序
核心思想:申请一个(max-min)+1 的桶, 将最小值作为基底。
代码:
func countingSort(a []int) {
aLen := len(a)
if aLen <= 1 {
return
}
//1. 找出数组a中,元素最大的数,申请切片
max := getMax(a)
//2. 申请max+1 切片,这样数组中的每个数都能保证有一个桶
//切片s,下标为a元素,值为元素个数,s为桶
s := make([]int, max+1)
//3. 遍历数组a,计算元素个数
for i := 0; i < aLen; i++ {
s[a[i]]++
}
//4. 顺序求数组和,目的是让统计数组存储的元素值,等于相应整数的最终排序位置。
//比如下标是9的元素值为5,代表原始数列的整数9,最终的排序是在第5位。
for i := 1; i <= max ; i++ {
s[i] = s[i-1] + s[i]
}
//5. 输出数组r,用于排好序的数组,大小应和数组a相同
r := make([]int, aLen)
//6. 将数组a从后向前遍历(可以保证稳定性), 并查询数组c中的个数,将 个数-1 作为下标存储在r中,并将 个数-1
for i := aLen-1; i >= 0; i-- {
//s[i]为对应数组元素的个数
index := s[a[i]] - 1
r[index] = a[i]
s[a[i]]--
}
//7. 将数组r 数据覆盖数组a数据
copy(a, r)
}
func getMax(a []int) int {
max := a[0]
for i := 1; i < len(a); i++ {
if a[i] > max {
max = a[i]
}
}
return max
}
复制代码
不足:如果一个要排序的数组数[90,92,93,90,91,97],则最大值为97,则申请的桶就为98,严重造成了资源的浪费,因为0-89下标没有任何用
优化:
func countingSort(a []int) {
aLen := len(a)
if aLen <= 1 {
return
}
//1. 找出数组a中,元素最大的数,以及元素最小的数,申请切片
max := getMax(a)
min := getMin(a)
//2. 申请max-min+1(不浪费内存) 切片,这样数组中的每个数都能保证有一个桶
//切片s,下标为a元素,值为元素个数
s := make([]int, max-min+1)
//3. 遍历数组a,计算元素个数(使用最小值作为基底,存储元素个数)
for i := 0; i < aLen; i++ {
s[a[i]-min]++
}
//4. 顺序求数组和,目的是让统计数组存储的元素值,等于相应整数的最终排序位置。
//比如下标是9的元素值为5,代表原始数列的整数9,最终的排序是在第5位。
for i := 1; i <= max-min; i++ {
s[i] = s[i-1] + s[i]
}
//5. 输出数组r,用于排好序的数组,大小应和数组a相同
r := make([]int, aLen)
//6. 将数组a从后向前遍历(可以保证稳定性), 并查询数组c中的个数,将 个数-1 作为下标存储在r中,并将 个数-1
for i := aLen-1; i >= 0; i-- {
//s[i]为对应数组元素的个数
index := s[a[i]-min] - 1
r[index] = a[i]
s[a[i]-min]--
}
//7. 将数组r 数据覆盖数组a数据
copy(a, r)
}
func getMax(a []int) int {
max := a[0]
for i := 1; i < len(a); i++ {
if a[i] > max {
max = a[i]
}
}
return max
}
func getMin(a []int) int {
min := a[0]
for i := 1; i < len(a); i++ {
if a[i] < min {
min = a[i]
}
}
return min
}
复制代码