前言

计算机课上,老师给一串数字6 1 6 9 9 1 4 2 1 5 8 8,问道:这一串数字,你们写个程序给我看,要求效率较高。学不出来的别下课了。

顿时场下一片哗然,但有很多小朋友硬着头皮啪啪啪的开始敲了。

老师走到pigpian身边,pigpian很难得皱了皱眉头

很难很难得写下了下面代码:

int a[]= {6,1,6,9,9,1,4,2,1,5,8,8};
for(int i=a.length-1;i>=0;i--)
{for(int j=0;j<i;j++){if(a[j]>a[j+1]){int team=a[j];a[j]=a[j+1];a[j+1]=team;}}
}
System.out.println(Arrays.toString(a));

老师:“gun吧,都2020年还用O(n2)得算法,快,快回去吃饭吧,快gun吧”。pigpian一脸无奈得走出教室,接着老师问道有没有其他人写出来,慢慢得挪到doudou得旁边。

doudou着急解释道:老师,你看我的O(nlogn)得快排算法:

int a[]= {6,1,6,9,9,1,4,2,1,5,8,8};
Arrays.sort(a);
System.out.println(Arrays.toString(a));

老师轻蔑得嘲讽道:“gun 吧,就知道投机取巧,我看你海!回去吃饭吧” 紧着着老师走到bigmao 的旁边,bigmao 给老师看了他的代码:

private static void quicksort(int [] a,int left,int right)
{int low=left;int high=right;//下面两句的顺序一定不能混,否则会产生数组越界!!!very important!!!if(low>high)return;int k=a[low];//取最左侧的一个作为衡量,最后要求左侧都比它小,右侧都比它大。while(low<high){while(low<high&&a[high]>=k){high--;}//这样就找到第一个比它小的了a[low]=a[high];while(low<high&&a[low]<=k){low++;}a[high]=a[low];          }a[low]=k;quicksort(a, left, low-1);quicksort(a, low+1, right);
}

老师脸角泛起微光:“不错不错,手写快排还是挺棒的,回去吃饭吧!”。

此时bigsai举起他的小手手:“老师快来,我写的这个贼快”。bigsai亮起他的代码:

int a[]= {6,1,6,9,9,1,4,2,1,5,8,8};
int count[]=new int[10];
for(int i=0;i<a.length;i++)
{count[a[i]]++;
}
int index=0;
for(int i=0;i<count.length;i++)
{while (count[i]-->0) {a[index++]=i;}
}
System.out.println(Arrays.toString(a));

"不错不错,这个方法效率确实很高,你回去把这种排序的方法和大家分享一下吧!"老师惊艳道!

bigsai出门后,站在门外的pigpiandoudou拦住问道:“sai哥这是啥东东啊”。

"计数排序。流程看图,听我下面慢慢讲:"

计数排序介绍

或许上面的代码你看起来还有点懵逼,但是不要紧,我们在这里给你讲明白什么是计数排序。对于计数排序,百度百科是这么说的:

计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(n*log(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(n*log(n)), 如归并排序,堆排序)

对于额外数组该如何理解呢?
我们慢慢来,在以前介绍桶排序的时候,我们知道每个桶里面是可以给一个范围的数字放进去。从每个桶的实质来看可以是List集合

但如果每个桶中只有一种元素,那么这个桶就可以不需要使用集合去储存标记,而是用一个数字即可进行标记认为它出现了多少次

所以这种每个桶只能放一种元素的,我们不需要每个桶再用List集合去装,而用数组的值储存对应编号出现的词数即可,例如上述的a[1]=2表示其中的1号桶出现两次,而a[3]=0表示元素3没有出现过。

而这样的数值如何计算呢?

  • 很简单,对待排序目标序列遍历一次,每次遍历的值让这个值的编号加上1,说明对应元素词数加一。例如上述第一个1就a[1]++,第二个5就a[5]++……
  • 然后取值时候遍历这个数字,顺序将目标编号的数字取出来即可。(每取一个对应位置数值减1直到为0为止)。例如上述遍历这个数组,就获得1 1 2 4 4 5这个序列。你看看,这个时间复杂度是不是O(n)的?

上面算法设计就很好了嘛?当然不是,如果是1,2 ,3之类数据肯定没啥问题,但是如果1000001,1000002,1000003之类的序列你这么开数组不是太多空间了?并且前面也要遍历很多无用的次数。

所以我们在设计具体算法的时候,先找到最小值min,再找最大值max。然后创建这个区间大小的数组,从min的位置开始计数,这样就可以最大程度的压缩空间,提高空间的使用效率。

代码实现

通过上述分析,计数排序的实现代码为:

import java.util.Arrays;public class test {public static void jishusort(int a[]){int min=Integer.MAX_VALUE;int max=Integer.MIN_VALUE;for(int i=0;i<a.length;i++)//找到max和min{if(a[i]<min) min=a[i];if(a[i]>max)max=a[i];}int count[]=new int[max-min+1];//对元素进行计数for(int i=0;i<a.length;i++){count[a[i]-min]++;}//排序取值int index=0;for(int i=0;i<count.length;i++){while (count[i]-->0) {a[index++]=i+min;//有min才是真正值}}}public static void main(String[] args) {int a[]= {6,1,6,9,9,1,4,2,1,5,8,8};jishusort(a);System.out.println(Arrays.toString(a));}}

打印结果为:

[1, 1, 1, 2, 4, 5, 6, 6, 8, 8, 9, 9]

结语

通过上面我想计数排序你已经搞得很清楚了,计数排序的时间复杂度为O(n+k)其中k为正数范围;线性时间大部分都比其他排序快一点,但是也不一定,例如你遇到1 2 4 2 100001这样一个序列,其中k的范围为10000,虽然他是O(n+k)=O(k)k远大于n情况,但是此时O(k)>O(nlogn)因为n太小,而K太大,需要遍历的词数太多了。

所以即使计数排序它是线性但是并非所有情况都是最好的方法,并且也占用了太多内存。当数据范围波动不是很大,数据相对比较集中,这时候用计数排序肯定是最好的啦,这点和桶排序的要求很像哦,没错,它其实就是一种特殊的桶排序,他的桶大小为1,用数值计数词数而以,其他都是一样的操作。

此时bigsai沾沾自喜终于讲完了,在旁边的pigpiandoudou直呼:讲的真的太好了,我不光要把它收藏下来,我还要给你点赞

bigsai笑了,心想光点赞哪里够

【排序算法】计数排序引发的围观风波——一种O(n)的排序相关推荐

  1. 三种线性排序算法 计数排序、桶排序与基数排序-BYVoid

    转自:BYVoid [非基于比较的排序] 在计算机科学中,排序是一门基础的算法技术,许多算法都要以此作为基础,不同的排序算法有着不同的时间开销和空间开销.排序算法有非常多种,如我们最常用的快速排序和堆 ...

  2. 三种线性排序算法 计数排序、桶排序与基数排序—— 转自:BYVoid

    三种线性排序算法 计数排序.桶排序与基数排序 [非基于比较的排序] 在计算机科学中,排序是一门基础的算法技术,许多算法都要以此作为基础,不同的排序算法有着不同的时间开销和空间开销.排序算法有非常多种, ...

  3. java常见排序算法有哪些_Java中常用的6种排序算法详细分解

    排序算法很多地方都会用到,近期又重新看了一遍算法,并自己简单地实现了一遍,特此记录下来,为以后复习留点材料. 废话不多说,下面逐一看看经典的排序算法: 1. 选择排序 选择排序的基本思想是遍历数组的过 ...

  4. 排序算法---计数排序(java版)

    计数排序 原理 计数排序(Counting Sort) 使用了一个额外的数组 C,其中第 i 个元素是待排序数组A 中值等于 i 的元素的个数.然后根据数组 C 来将 A 中的元素排到正确的位置.其实 ...

  5. 排序算法——计数排序详解

    在排序的最终结果中,各元素的次序依赖于它们之间的比较.这类排序算法被称为比较排序.对于包含 nnn 个元素的输入序列来说,任何比较排序算法在最坏情况下都要经过至少 O(nlogn)O(n\ log\ ...

  6. 十大排序算法——计数排序

    计数排序 一. 计数排序介绍 二. 计数排序基础版 三. 计数排序改进版 四. 优化最终版本_空间节省 一. 计数排序介绍 计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个 ...

  7. 比较排序算法的时间复杂度 c语言,c语言四种排序算法时间复杂度比较(10页)-原创力文档...

    1.方案设计: 我这次实验通过随机生成30000个随机数,把随机数存到数组中,用这同一组随机数据分别进行四种排序,直接插入排序.直接选择排序.冒泡排序和快速排序.还通过了调用txt文件把运算所需时间导 ...

  8. 排序算法(分类,时间复杂度)(快速排序,插入排序,希尔排序,选择排序,冒泡排序)

    1.排序算法 1.排序的分类 分为内部排序和外部排序,其中内部排序分为插入排序.选择排序.交换排序.归并排序和基数排序.插入排序包括直接插入排序和希尔排序:选择排序包括简单选择排序和堆排序:交换排序包 ...

  9. 【vlfeat】O(n)排序算法——计数排序

    今天想在网上找一个实现好的er算法来着,没啥具体的资料,无奈只能看vlfeat的mser源码,看能不能修修补补实现个er. 于是,看到某一段感觉很神奇,于是放下写代码,跑来写博客,也就是这段 1 /* ...

最新文章

  1. 网络管理经验谈:初级网管的网络安全
  2. Gitlab服务器搭建
  3. 系统管理-第1部分 系统的易管理性
  4. matlab 画图比例缩小图片大小,Matlab 画图字体,字号的设定,图片大小和比例
  5. ITK:将ITK灰度图像转换为CV :: Mat
  6. SSM框架下log4j的配置和使用
  7. eclipse源服务器未能找到,eclipse - HTTP状态[404]? [未找到](原始服务器未找到当前表示) - 堆栈内存溢出...
  8. c# task添加顺序_关于c#:Task和async等待所需的指导
  9. Qt DLL总结【三】-VS2008+Qt 使用QPluginLoader访问DLL
  10. Excel 【数据透视表】 -【动态表图】 之核心 -【切片器】
  11. ELK详解(四)——Head插件安装
  12. (转)区块链热潮背后的五大技术隐忧
  13. [Unity插件]Live2D插件学习
  14. 2022美国大学生数学建模竞赛(美赛)思路代码
  15. python 修改pdf_使用Python编辑PDF
  16. 小飞鱼通达二开 通达OA集成企业微信扫码登录的开发(图文)
  17. 程序员工作三年晒出工资条,直言加班太累了,网友评论炸锅
  18. 一个控制键盘远程控制多台视频会议摄像机(转自搜狐)
  19. android 高德地图GPS点校正
  20. C语言(C++语言)中##(两个井号)和#(一个井号)用法[转]

热门文章

  1. (chap3 数据链路) 数据链路概览
  2. 《研磨设计模式》chap25 访问者模式Visitor(1)模式介绍
  3. 编译Bitcoin BCH configure: error: libdb_cxx headers missing ,终于解决了
  4. Windows SID理解
  5. 数据结构与算法——树与二叉树详细分享
  6. while((ch=getchar())!=EOFch != '\n');消除非法输入
  7. 彻底明白TCP的三次握手与四次挥手
  8. 重游java(猜拳项目)
  9. 【CTF大赛】第五届XMan选拔赛 ezCM Writeup
  10. 【Shell】设置变量默认值,参数默认值, 自动赋值