常用的排序算法之计数排序(Counting Sort)
计数排序(Counting Sort)
原理
计数排序(Counting Sort)的起源并不明确指向某一个特定的发明者或时间点,但它作为一种简单直观的排序算法,在计算机科学中得到了广泛的应用。计数排序的基本思想是通过统计数组中每个元素出现的次数,来确定其在排序后数组中的位置。
定义
计数排序是一种非基于比较的排序算法,适用于一定范围内的整数排序。它将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
引伸义
计数排序的主要思想是通过“计数”来排序,即统计每个元素出现的次数,然后根据这个次数来确定元素在排序后数组中的位置。这种方法避免了传统比较排序算法中的重复比较,从而实现了线性的时间复杂度。
优缺点
优点:
- 时间复杂度低,为O(n+k)(n为待排序数组长度,k为待排序数组中元素的取值范围)。
- 稳定性好,相等的元素在排序后保持原有的相对顺序。
- 空间复杂度为O(k),其中k为待排序数组中元素的取值范围。
缺点:
- 当k很大时,需要消耗大量空间。
- 只适用于整数排序,且要求待排序数组中的元素非负。
使用场景
计数排序适用于待排序数组元素取值范围较小且非负的场景,如考试成绩排序(假设分数范围为0-100)等。
使用数据一步步举例
假设有一个待排序数组arr = [4, 2, 2, 8, 3, 3, 1]
,其元素取值范围为1-9。
-
初始化一个长度为10(取值范围+1)的计数数组
count
,并将所有元素初始化为0。1count = [
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
]
-
遍历待排序数组
arr
,统计每个元素出现的次数,并将计数数组对应位置的值加1。12arr: [
4
,
2
,
2
,
8
,
3
,
3
,
1
]
count 变为: [
1
,
1
,
2
,
2
,
1
,
0
,
0
,
0
,
1
,
0
]
-
修改计数数组,使得每个位置的值变为小于等于该值的元素个数。
1count 变为: [
0
,
1
,
2
,
4
,
5
,
5
,
5
,
5
,
6
,
6
]
-
从后往前遍历待排序数组
arr
,将每个元素放到排序后数组sortedArr
的count[arr[i]]-1
位置,并更新count[arr[i]]
的值。1234sortedArr = []
for
i from len(arr) -
1
to
0
:
sortedArr.insert(count[arr[i]] -
1
, arr[i])
count[arr[i]] -=
1
排序后的数组
sortedArr
为[1, 2, 2, 3, 3, 4, 8]
。
Java示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | public class CountingSort { // 查找数组中的最大值 private static int findMaxValue( int [] arr) { int maxValue = arr[ 0 ]; for ( int i = 1 ; i < arr.length; i++) { if (arr[i] > maxValue) { maxValue = arr[i]; } } return maxValue; } // 计数排序方法 public static void countingSort( int [] arr) { if (arr == null || arr.length == 0 ) return ; int maxValue = findMaxValue(arr); int [] count = new int [maxValue + 1 ]; // 统计每个元素出现的次数 for ( int i = 0 ; i < arr.length; i++) { count[arr[i]]++; } // 修改count数组,使得每个位置的值变为小于等于该值的元素个数 for ( int i = 1 ; i <= maxValue; i++) { count[i] += count[i - 1 ]; } // 从后往前遍历arr,将元素放到正确的位置 int [] sortedArr = new int [arr.length]; for ( int i = arr.length - 1 ; i >= 0 ; i--) { sortedArr[count[arr[i]] - 1 ] = arr[i]; count[arr[i]]--; } // 将排序后的数组复制回原数组 System.arraycopy(sortedArr, 0 , arr, 0 , arr.length); } // 主方法,用于测试计数排序 public static void main(String[] args) { int [] arr = { 4 , 2 , 2 , 8 , 3 , 3 , 1 }; System.out.println( "Original array: " + Arrays.toString(arr)); countingSort(arr); System.out.println( "Sorted array: " + Arrays.toString(arr)); } } |
在这段代码中,我添加了一个findMaxValue
方法来查找数组中的最大值,以便正确地初始化计数数组count
的大小。然后,我添加了一个main
方法来测试countingSort
方法。main
方法创建了一个示例数组,打印出原始数组,调用countingSort
方法进行排序,并打印出排序后的数组。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?