前言:

计数排序是了解基数排序的基石之一,同时也是基数排序中用的最广泛的两种排序算法之一(还有一个是桶排序)。计数排序的时间复杂度很低,但是空间复杂度比较高,这是它的制约因素。

我写的这个计数排序不能解决数组中出现负数的问题。但是出现负数其实很简单——我这个的实现是数组向左偏移实现对齐;如果有负数的话,我只需要找到最小的负数,并且让数组中所有数字向右偏移对齐就可以了,实现起来也是基本差不多,就不另外写了。

思路:

对一堆数字进行排序不用两两比较,我们只需要创造许多容器(有序),把数组元素一一对应的放进去,然后顺序读取容器中的值就可以了。这个计数排序就是这么个思路。但是,我们如果把元素的值当做下标,未免太浪费空间,所以我选择将元素向左偏移,让最小的元素下标为0,节省一点点空间。

首先,我们需要一个辅助的计数数组和一个为了方便存储元素的和原数组一样大的数组空间。创建空间就最好先进行初始化,免得后面出问题。

那么计数数组的空间应该多大?应该是数组中值 max - min + 1 的大小。我写在外头单独封装。

int find_count_len(int* a, int len)
{int min = a[0], max = a[0];int i;int count = 0;for (i = 0; i < len; i++){count++;if (a[i] > max)max = a[i];if (a[i] < min)min = a[i];}printf("传入元素个数:%d\n", count);printf("数组最大值:%d\n数组最小值:%d\n", max, min);printf("计数数组长度为:%d\n", max - min + 1);return max - min + 1;
}

创建空间的同时也顺带找一下偏移量,其实就是数组中最小的元素

int count_arr_len = find_count_len(a, len);
int* count_arr = (int*)malloc(sizeof(int) * count_arr_len);
int i;
for (i = 0; i < count_arr_len; i++)count_arr[i] = 0;//找偏移量:就是数组中最小的值
int offset = a[0];
for (i = 1; i < len; i++)if (a[i] < offset)offset = a[i];//存放有序数组的空间
int* b = (int*)malloc(sizeof(int) * len);

然后我我们给计数数组开始计数:(每个相同的元素在相同的计数下标下+1),a[i] - offset 是偏移以后的计数数组的下标。

for (i = 0; i < len; i++)count_arr[a[i] - offset]++;

接着累加计数数组,这一步的作用是在之后读入数字的时候可以从后往前排序,为了让计数排序成为稳定的排序,不打乱元素之间的相对位置。

//累加计数数组,得到偏移下标
for (i = 1; i < count_arr_len; i++)count_arr[i] += count_arr[i - 1];

最后是最核心的排序部分,核心思想就是把原数组中的元素,通过计数数组得到他在有序数组中的下标,然后读进去,代码很简单,但需要理解。画个图,多用手模拟几遍就懂了。

for (i = len; i > 0; i--)b[--count_arr[a[i - 1] - offset]] = a[i - 1];

最后就是我们排序的是传入的数组a,我们需要将辅助数组中的值迁移到a中。选择用哪种方式迁移都可以,除了地址互换(辅助数组是要free掉的,会报错)。

下面是排序的核心代码:

void generate_random_number(int*, int, int);
void swap(int*, int*);
int find_count_len(int* a, int len)
{int min = a[0], max = a[0];int i;int count = 0;for (i = 0; i < len; i++){count++;if (a[i] > max)max = a[i];if (a[i] < min)min = a[i];}return max - min + 1;
}void CountingSort(int* a, int len)
{int count_arr_len = find_count_len(a, len);int* count_arr = (int*)malloc(sizeof(int) * count_arr_len);int i;for (i = 0; i < count_arr_len; i++)int offset = a[0];for (i = 1; i < len; i++)if (a[i] < offset)offset = a[i];int* b = (int*)malloc(sizeof(int) * len);//计数数组开始计数for (i = 0; i < len; i++)count_arr[a[i] - offset]++;//累加计数数组,得到偏移下标for (i = 1; i < count_arr_len; i++)count_arr[i] += count_arr[i - 1];for (i = len; i > 0; i--)b[--count_arr[a[i - 1] - offset]] = a[i - 1];for (i = 0; i < len; i++)swap(&a[i], &b[i]);free(count_arr);count_arr = NULL;free(b);b = NULL;
}

示例代码:

这个排序由于我一开始写老是错,所以我写的时候加了很多的测试信息,因此随机数生成范围我把他变小了一点,这样计数数组方便进行观察。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 30
//之前写过了,就不再全写一遍了
void generate_random_number(int*, int, int);
void swap(int*, int*);int find_count_len(int* a, int len)
{int min = a[0], max = a[0];int i;int count = 0;for (i = 0; i < len; i++){count++;if (a[i] > max)max = a[i];if (a[i] < min)min = a[i];}printf("传入元素个数:%d\n", count);printf("数组最大值:%d\n数组最小值:%d\n", max, min);printf("计数数组长度为:%d\n", max - min + 1);return max - min + 1;
}void CountingSort(int* a, int len)
{int count_arr_len = find_count_len(a, len);int* count_arr = (int*)malloc(sizeof(int) * count_arr_len);int i;for (i = 0; i < count_arr_len; i++)count_arr[i] = 0;//找偏移量:就是数组中最小的值int offset = a[0];for (i = 1; i < len; i++)if (a[i] < offset)offset = a[i];printf("偏移量为:%d\n", offset);//存放有序数组的空间int* b = (int*)malloc(sizeof(int) * len);//计数数组开始计数for (i = 0; i < len; i++)count_arr[a[i] - offset]++;//testprintf("原计数数组:\n");for (i = 0; i < count_arr_len; i++)printf("%d ", count_arr[i]);printf("\n");//累加计数数组,得到偏移下标for (i = 1; i < count_arr_len; i++)count_arr[i] += count_arr[i - 1];//testprintf("更新后计数数组:\n");for (i = 0; i < count_arr_len; i++)printf("%d ", count_arr[i]);printf("\n");for (i = len; i > 0; i--)b[--count_arr[a[i - 1] - offset]] = a[i - 1];//testprintf("数组b[]:\n");for (i = 0; i < len; i++)printf("%d ", b[i]);printf("\n");for (i = 0; i < len; i++)swap(&a[i], &b[i]);free(count_arr);count_arr = NULL;free(b);b = NULL;
}int main()//13
{int arr[N + 5] = { 0 };generate_random_number(arr, 0, 30);CountingSort(arr, N);printf("排序完数组为:\n");for (int i = 0; i < N; i++)printf("%d ", arr[i]);printf("\n");return 0;
}

测试结果:

CountingSort(计数排序)——C语言实现相关推荐

  1. JavaScript实现CountingSort计数排序算法(附完整源码)

    JavaScript实现CountingSort计数排序算法(附完整源码) Comparator.js完整源代码 Sort.js完整源代码 CountingSort.js完整源代码 Comparato ...

  2. [计数排序]统计三个数和的[最大概率](洛谷P2911题题解,Java语言描述)

    题目要求 P2911题目链接 分析 我用暴力思想做的,对每种和进行计数. 暴力的基本思想是计数排序,开一个数组,计数最后按照要求得到结果. 遍历的过程就很暴力哈哈哈-- 这位大神用期望做的,Orz → ...

  3. C语言计数排序Counting sort 算法(附完整源码)

    计数排序Counting sort 算法 计数排序Counting sort 算法的完整源码(定义,实现,main函数测试) 计数排序Counting sort 算法的完整源码(定义,实现,main函 ...

  4. 【八大排序详解~C语言版】直接插入排序-希尔排序- 直接选择排序-堆排序-冒泡排序-快速排序-归并排序-计数排序

    八大排序 1.直接插入排序 2.希尔排序 3.直接选择排序 直接选择排序改进 4.堆排序 1.建堆 2.利用堆删除思想来进行排序 5.冒泡排序 6.快速排序 递归实现 非递归实现 7.归并排序 递归实 ...

  5. 算法导论——计数排序

    2019独角兽企业重金招聘Python工程师标准>>> /*** 计数排序* * 不用比较的排序算法,时间可以突破O(NlgN)* * 时间复杂度O(N),稳定* * 适用于所有需要 ...

  6. 算法——计数排序与快速排序

    计数排序是一种算法复杂度 O(n) 的排序方法,适合于小范围集合的排序.比如100万学生参加高考,我们想对这100万学生的数学成绩(假设分数为0到100)做个排序.我们如何设计一个 最高效的排序算法. ...

  7. 计数排序,基数排序,桶排序

    转 http://blog.163.com/yuyang_tech/blog/static/216050083201382055821953/ 与合并排序,堆排序,快速排序等基于比较的排序算法不同,计 ...

  8. 排序算法之计数排序、基数排序和桶排序

    转自:http://www.cnblogs.com/ttltry-air/archive/2012/08/04/2623302.html 计数排序,基数排序,桶排序等非比较排序算法,平均时间复杂度都是 ...

  9. 计数排序及其改进 C++代码实现与分析 恋上数据结构笔记

    文章目录 复习梗概 算法思想 基础思想 改进空间复杂度,改进不能对负数进行排序问题 改进稳定性 计数排序时间空间复杂度 计数排序基础版 代码及输出 计数排序第一次改进版 代码及输出 计数排序终极版 代 ...

  10. java最全基础知识_Java编程入门,计数排序(Counting Sort)怎么做?

    计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中. 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数. 计数排序(Counting sort)是一种稳定的排 ...

最新文章

  1. nginx技术(2)nginx的配置详解
  2. [ubuntu]dlna平台搭建(在家里,寝室搭建自己的影音平台)
  3. VMware介绍与网络的三种模式
  4. 04_NoSQL数据库之Redis数据库:set类型和zset类型
  5. Java Optional学习笔记
  6. C# 控制台 模拟时间一秒一秒走动,直到按Esc键,时间静止,退出!
  7. java 原子量_JAVA线程10 - 新特性:原子量
  8. Linux驱动段错误,linux驱动调试--段错误之oops信息分析
  9. 算法分析-插入排序INSERT_SORT与选择排序SELECT_SORT【线性方法】
  10. mysql 删除后缀表_mysql批量删除指定前缀或后缀表
  11. java 主类 测试类_Java中的测试类和主类分别是什么,有点晕啊。?
  12. JAVA自学知识点评定标准--自尚学堂马士兵
  13. mac 怎么抓取 iphone 手机 日志
  14. 采用软改的方式激活Windows 7
  15. 2021CCPC网络预选赛
  16. Unity Obi插件修改到支持URP
  17. POWER BI filter函数的筛选条件可以使用度量值作为筛选条件
  18. win10系统vvv连接不上,提示:“在连接完成前,连接被远程计算机终止”的解决办法
  19. Aspose.Imaging for .NET V23
  20. QuickTime 专业版 pro 注册码

热门文章

  1. 【漏洞】——心脏滴血(CVE-2014-0160)
  2. Blockstack: A Global Naming and Storage System Secured by Blockchains
  3. vmoptions默认配置_VM options 以及 properties文件的一些理解
  4. rtx web 分级管理系统 二次开发
  5. Android EagleEye笔记
  6. 【论文笔记】Graph U-Nets
  7. 计算机桌面图标变白色,桌面图标变白色文档该怎么办?-电脑自学网
  8. vue项目打包后index.html文件打开空白
  9. 最好的开源网络入侵检测工具
  10. python中pow函数用法_Python pow()用法及代码示例