常用的排序算法之计数排序(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。count = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-
遍历待排序数组
arr
,统计每个元素出现的次数,并将计数数组对应位置的值加1。arr: [4, 2, 2, 8, 3, 3, 1] count 变为: [1, 1, 2, 2, 1, 0, 0, 0, 1, 0]
-
修改计数数组,使得每个位置的值变为小于等于该值的元素个数。
count 变为: [0, 1, 2, 4, 5, 5, 5, 5, 6, 6]
-
从后往前遍历待排序数组
arr
,将每个元素放到排序后数组sortedArr
的count[arr[i]]-1
位置,并更新count[arr[i]]
的值。sortedArr = [] 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示例代码
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
方法进行排序,并打印出排序后的数组。