计数排序法

Posted 算法精解

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计数排序法相关的知识,希望对你有一定的参考价值。

简介

计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(n*log(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(n*log(n)), 如归并排序,堆排序)

算法过程

  1. 根据待排序集合中最大元素和最小元素的差值范围,申请额外空间;

  2. 历待排序集合,将每一个元素出现的次数记录到元素值对应的额外空间内;

  3. 对额外空间内数据进行计算,得出每一个元素的正确位置;

  4. 将待排序集合每一个元素移动到计算得出的正确位置上

算法实现

计数排序Golang代码如下。

func CountSort(arr []int) []int { res := make([]int, len(arr)) min, max := arr[0], arr[0] for _, v:= range arr { if v > max { max = v } else if v < min { min = v } } // 取排序数组中,元素大小的极值差+1 k := max - min + 1 counts := make([]int, k) for _, v := range arr { counts[v - min]++ } for i := 1; i < len(counts); i++ { counts[i] += counts[i - 1] } for i := len(arr) - 1; i >= 0; i-- { res[counts[arr[i] - min] - 1] = arr[i] } return res}
测试用例
func TestCountSort(t *testing.T) { rand.Seed(time.Now().Unix()) var arr []int for i := 0; i < 10; i++ { temp := rand.Intn(1000) arr = append(arr, temp) } originSort := append([]int{}, arr...) sort.Ints(originSort) res := countSort.CountSort(arr) if !reflect.DeepEqual(originSort, res) { t.Errorf("Got %v for input %v; expected %v", res, arr, originSort) }}

测试结果如图1所示。

图1 测试结果

算法分析

由算法示例可知,计数排序的时间复杂度为 Ο(n+k)。因为算法过程中需要申请一个额外空间和一个与待排序集合大小相同的已排序空间,所以空间复杂度为Ο(n+k) 。由此可知,计数排序只适用于元素值较为集中的情况,若集合中存在最大最小元素值相差甚远的情况,则计数排序开销较大、性能较差。通过额外空间的作用方式可知,额外空间存储元素信息是通过计算元素与最小元素值的差值作为下标来完成的,若待排序集合中存在元素值为浮点数形式或其他形式,则需要对元素值或元素差值做变换,以保证所有差值都为一个非负整数形式。

以上是关于计数排序法的主要内容,如果未能解决你的问题,请参考以下文章

js冒泡排序法——选择排序(other)——计数排序(桶排序)——快速排序——插入排序-更新

数据结构之排序算法Java实现—— 基数排序法

计数排序法

找到多个名为 [spring_web] 的片段。这对于相对排序是不合法的

排序02-直接插入排序法

冒泡法