计数排序 (Counting Sort)

本文介绍了一种稳定的排序算法——计数排序。详细解释了计数排序的工作原理、适用场景及其实现步骤,并提供了C语言实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:wiki : http://en.wikipedia.org/wiki/Counting_sort
http://zh.wikipedia.org/wiki/%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F


计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。

计数排序的特征

当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。

由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。

算法的步骤如下:

  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加) (记录小于它的元素个数,用来计算它在整体整体中的排名)
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

In pseudocode, this may be expressed as follows:

''' calculate histogram: '''
# allocate an array Count[0..k] ; THEN
# initialize each array cell to zero ; THEN
for each input item x:
    increment Count[key(x)]
 
''' calculate starting index for each key: '''
total = 0
for i = 0, 1, ... k:
    oldCount = Count[i]
    Count[i] = total
    total = total + oldCount
 
''' copy inputs into output array in order: '''
# allocate an output array Output[0..n-1] ; THEN
for each input item x:
    Output[Count[key(x)]] = x
    decrement Count[key(x)]
return Output

After the first for loop, Count[i] stores the number of items with key equal to i.After the second for loop, it instead stores the number of items with key less than i, which is the same as the first index at which an item with keyi should be stored in the output array. Throughout the third loop,Count[i] always stores the next position in the output array into which an item with key i should be stored, so each item is moved into its correct position in the output array. The relative order of items with equal keys is preserved here; i.e., this is a stable sort.


我写的代码: (最新修改 2013-12-12)


/*
 * 计数排序: 稳定的排序
 * huntinux
 * 13-12-12
 *
 */

#include <stdio.h>
#include <malloc.h>

int find_max(int *a, int n)
{
	int i;
	int max = a[0];

	for(i = 1; i < n; i++){
		if(a[i]>max)
			max = a[i];
	}
	return max;
}

void counting_sort(int *a, int n)
{
    int *count, *tmparr;
    int i;
    int size;

    size = find_max(a,n); // 找到最大元素	
    size += 1; // 因为数据从0开始,所以要多申请一个。
    size = size > n ? size : n; //元素个数和最大元素之间较大的作为计数数组的大小。

    count = malloc(sizeof(int) * size );
    if(!count)
        perror("malloc");
    for(i = 0; i < size; i++)
        count[i] = 0;
    
    for(i = 0; i < n; i++)
        count[a[i]]++;

    for(i = 1; i < size; i++)
        count[i] += count[i-1];

    tmparr = malloc(sizeof(int) * n);
    if(!tmparr)
        perror("malloc");
    for(i = 0; i < n; i++)
        tmparr[i] = 0;

    for(i = n-1; i >= 0; i--) //这里让i从n-1开始,是保证在数字相等的情况下,默认靠前的数字要排在前面。(保证稳定排序)
        tmparr[--count[a[i]]] = a[i];

    for(i = 0; i < n; i++)
        a[i] = tmparr[i];

    free(count);
    free(tmparr);
}

void print_arr(int *a, int n, char *msg)
{
    int i;
    
    if(msg)
        printf("%s\n", msg);

    for(i = 0; i < n; i++)
        printf("%d\t", a[i]);
    printf("\n");

}


int main()
{
    int a[15] = {8, 4 , 2, 6, 3, 1, 9, 3, 5, 7, 1, 100, 0, 2, 5};

    print_arr(a, 15, "before sorting:");
    counting_sort(a, 15);
    print_arr(a, 15, "after sorting:");

    return 0;
}



注意下面的代码是保证稳定排序的关键:

for(i = n-1; i >= 0; i--) //这里让i从n-1开始,是保证在数字相等的情况下,默认靠前的数字要排在前面。(保证稳定排序)
		tmparr[--count[a[i]]] = a[i];

### Python 计数排序Counting Sort)算法实现 计数排序是一种非比较型整数排序算法,适用于数据范围较小的整数排序。该算法通过统计每个值出现的次数来进行排序。 #### 计数排序的核心思想 对于给定的一个数组 `arr` ,找到最大值 `max_val` 并创建一个长度为 `max_val + 1` 的辅助数组 `count` 。这个辅助数组用来记录原数组中各个数值出现的频次。最后再根据频次重构有序的新列表[^1]。 下面是具体的Python代码实现: ```python def counting_sort(arr): if not arr: # 处理空数组的情况 return [] max_val = max(arr) # 获取数组中的最大值 min_val = min(arr) # 获取最小值以便处理负数 offset = -min_val # 偏移量用于支持负数 m = max_val + offset + 1 # 考虑偏移后的大小 count = [0] * m # 初始化频率表 for a in arr: count[a + offset] += 1 # 统计各元素的数量 result = [] # 构建结果集 for i in range(len(count)): while count[i] > 0: # 将相同数量的i加入result result.append(i - offset) count[i] -= 1 return result # 返回已排序的结果 ``` 此版本不仅能够处理正整数还可以处理包含负数的数据集合[^2]。 为了验证上述函数的有效性,可以使用如下测试案例: ```python # 测试用例 test_cases = [ ([1,4,1,2,7,5,2], [1,1,2,2,4,5,7]), ([3,-1,2,-1,0], [-1,-1,0,2,3]) ] for case in test_cases: print(f"原始数组:{case[0]}") print(f"排序结果:{counting_sort(case[0])}") print(f"期望结果:{case[1]}\n") ``` 以上实现了对含有正整数以及含负数两种情况下计数排序的功能展示,并且保持了算法的时间复杂度为线性的特性即O(n)[^4]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值