From c837882dbd7c75bb12247675f8c21ff722ec4d0c Mon Sep 17 00:00:00 2001 From: Reanon <793584285@qq.com> Date: Mon, 20 Mar 2023 21:16:25 +0800 Subject: [PATCH] feat(counting_sort): support counting_sort in c/go (#431) * feat(go/counting_sort): support counting_sort in go * feat(test): support counting_sort_naive testcase * feat(go/counting_sort): support counting sort * feat(c/counting_sort): support counting_sort in c --- .gitignore | 1 - codes/c/chapter_sorting/CMakeLists.txt | 1 + codes/c/chapter_sorting/counting_sort.c | 81 +++++++++++++++++++++ codes/go/chapter_sorting/count_sort_test.go | 20 +++++ codes/go/chapter_sorting/counting_sort.go | 66 +++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 codes/c/chapter_sorting/counting_sort.c create mode 100644 codes/go/chapter_sorting/count_sort_test.go create mode 100644 codes/go/chapter_sorting/counting_sort.go diff --git a/.gitignore b/.gitignore index 65f68683e..e2548c5da 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,3 @@ docs/overrides/ build/ site/ utils/ -**/cmake-build-debug diff --git a/codes/c/chapter_sorting/CMakeLists.txt b/codes/c/chapter_sorting/CMakeLists.txt index e6c097be6..5de59ae18 100644 --- a/codes/c/chapter_sorting/CMakeLists.txt +++ b/codes/c/chapter_sorting/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(bubble_sort bubble_sort.c) +add_executable(counting_sort counting_sort.c) add_executable(insertion_sort insertion_sort.c) add_executable(quick_sort quick_sort.c) add_executable(radix_sort radix_sort.c) \ No newline at end of file diff --git a/codes/c/chapter_sorting/counting_sort.c b/codes/c/chapter_sorting/counting_sort.c new file mode 100644 index 000000000..e0dcdec45 --- /dev/null +++ b/codes/c/chapter_sorting/counting_sort.c @@ -0,0 +1,81 @@ +/** + * File: counting_sort.c + * Created Time: 2023-03-20 + * Author: Reanon (793584285@qq.com) + */ +#include "../include/include.h" + +/* 计数排序 */ +// 简单实现,无法用于排序对象 +void countingSortNaive(int nums[], int size) { + // 1. 统计数组最大元素 m + int m = 0; + for (int i = 0; i < size; i++) { + if (nums[i] > m) { + m = nums[i]; + } + } + // 2. 统计各数字的出现次数 + // counter[num] 代表 num 的出现次数 + int *counter = malloc(sizeof(int) * size); + for (int i = 0; i < size; i++) { + counter[nums[i]]++; + } + // 3. 遍历 counter ,将各元素填入原数组 nums + int i = 0; + for (int num = 0; num < m + 1; num++) { + for (int j = 0; j < counter[num]; j++, i++) { + nums[i] = num; + } + } +} + + +/* 计数排序 */ +// 完整实现,可排序对象,并且是稳定排序 +void countingSort(int nums[], int size) { + // 1. 统计数组最大元素 m + int m = 0; + for (int i = 0; i < size; i++) { + if (nums[i] > m) { + m = nums[i]; + } + } + // 2. 统计各数字的出现次数 + // counter[num] 代表 num 的出现次数 + int *counter = malloc(sizeof(int) * size); + for (int i = 0; i < size; i++) { + counter[nums[i]]++; + } + // 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引” + // 即 counter[num]-1 是 num 在 res 中最后一次出现的索引 + for (int i = 0; i < m; i++) { + counter[i + 1] += counter[i]; + } + // 4. 倒序遍历 nums ,将各元素填入结果数组 res + // 初始化数组 res 用于记录结果 + int *res = malloc(sizeof(int) * size); + for (int i = size - 1; i >= 0; i--) { + int num = nums[i]; + // 将 num 放置到对应索引处 + res[counter[num] - 1] = num; + // 令前缀和自减 1 ,得到下次放置 num 的索引 + counter[num]--; + } + // 使用结果数组 res 覆盖原数组 nums + memcpy(nums, res, size * sizeof(int)); +} + +/* Driver Code */ +int main() { + int nums[] = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4}; + int size = sizeof(nums) / sizeof(int); + countingSortNaive(nums, size); + printf("计数排序(无法排序对象)完成后 nums = "); + printArray(nums, size); + + countingSort(nums, size); + printf("计数排序完成后 nums = "); + printArray(nums, size); + return 0; +} \ No newline at end of file diff --git a/codes/go/chapter_sorting/count_sort_test.go b/codes/go/chapter_sorting/count_sort_test.go new file mode 100644 index 000000000..8358a9935 --- /dev/null +++ b/codes/go/chapter_sorting/count_sort_test.go @@ -0,0 +1,20 @@ +// File: count_sort_test.go +// Created Time: 2023-03-20 +// Author: Reanon (793584285@qq.com) + +package chapter_sorting + +import ( + "fmt" + "testing" +) + +func TestCountingSort(t *testing.T) { + c := &CountingSort{} + nums := []int{1, 0, 1, 2, 0, 4, 0, 2, 2, 4} + c.countingSortNaive(nums) + fmt.Println("计数排序(无法排序对象)完成后 nums = ", nums) + + c.countingSort(nums) + fmt.Println("计数排序完成后 nums = ", nums) +} diff --git a/codes/go/chapter_sorting/counting_sort.go b/codes/go/chapter_sorting/counting_sort.go new file mode 100644 index 000000000..d52c6cd2b --- /dev/null +++ b/codes/go/chapter_sorting/counting_sort.go @@ -0,0 +1,66 @@ +// File: counting_sort.go +// Created Time: 2023-03-20 +// Author: Reanon (793584285@qq.com) + +package chapter_sorting + +type CountingSort struct{} + +/* 计数排序 */ +// 简单实现,无法用于排序对象 +func (c *CountingSort) countingSortNaive(nums []int) { + // 1. 统计数组最大元素 m + m := 0 + for num := range nums { + if num > m { + m = num + } + } + // 2. 统计各数字的出现次数 + // counter[num] 代表 num 的出现次数 + counter := make([]int, m+1) + for _, num := range nums { + counter[num]++ + } + // 3. 遍历 counter ,将各元素填入原数组 nums + for i, num := 0, 0; num < m+1; num++ { + for j := 0; j < counter[num]; j++ { + nums[i] = num + i++ + } + } +} + +func (c *CountingSort) countingSort(nums []int) { + // 1. 统计数组最大元素 m + m := 0 + for num := range nums { + if num > m { + m = num + } + } + // 2. 统计各数字的出现次数 + // counter[num] 代表 num 的出现次数 + counter := make([]int, m+1) + for _, num := range nums { + counter[num]++ + } + // 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引” + // 即 counter[num]-1 是 num 在 res 中最后一次出现的索引 + for i := 0; i < m; i++ { + counter[i+1] += counter[i] + } + // 4. 倒序遍历 nums ,将各元素填入结果数组 res + // 初始化数组 res 用于记录结果 + n := len(nums) + res := make([]int, n) + for i := n - 1; i >= 0; i-- { + num := nums[i] + // 将 num 放置到对应索引处 + res[counter[num]-1] = num + // 令前缀和自减 1 ,得到下次放置 num 的索引 + counter[num]-- + } + // 使用结果数组 res 覆盖原数组 nums + copy(nums, res) +}